Exploring lookup types, I'm interested in creating a safe-merge utility function that can update an entity of type T
with a subset of keys from another object. The objective is to leverage the TypeScript compiler to catch any misspelled properties or attempts to append non-existing ones for T
.
For example, I have a Person
interface and utilize the built-in Partial
type (introduced in v2.1) as follows:
interface Person {
name: string
age: number
active: boolean
}
function mergeAsNew<T>(a: T, b: Partial<T>): T {
return Object.assign({}, a, b);
}
I then apply this to specific data instances like so:
let p: Person = {
name: 'john',
age: 33,
active: false
};
let newPropsOk = {
name: 'john doe',
active: true
};
let newPropsErr = {
fullname: 'john doe',
enabled: true
};
mergeAsNew(p, newPropsOk);
mergeAsNew(p, newPropsErr); // <----- I want tsc to yell at me here because of trying to assign non-existing props
The idea is to trigger a TypeScript error on the second invocation since `fullname` and `enabled` are not properties of the `Person` interface. However, while this compiles locally without issues, the output differs when I run it in the online TS Playground.
Bonus question:
When attempting the following assignment:
let x: Person = mergeAsNew(p, newPropsOk);
An error arises specifically in the playground environment stating that `'age' is missing in type '{ name: string; active: boolean; }'. This discrepancy puzzles me as the input arguments align with the `Person` interface structure. Shouldn't `x` be considered of type `Person`?
EDIT: Below is my `tsconfig.json` configuration:
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"noEmitOnError": true,
"allowJs": false,
"sourceMap": true,
"strictNullChecks": true
},
"exclude": ["dist", "scripts"]
}