Below is a sample function; I want to define a generic IncompleteVariant
that's properties are defined as having the same types as that of T
but IncompleteVariant
has all of T
's properties as potentially unset.
Theoretically a IncompleteVariant<T>
should be allowed to be equal to {}
.
/**
* Modifies the passed `newState` to fallback on the `initialState` if any property is not set.
*/
export function orInitialState<T extends object> (newState: IncompleteVariant<T>, initialState: T): T {
type Key = keyof T;
if(!newState) return initialState;
const newerState: T = {...initialState}
for(const key of Object.keys(initialState)) {
if(newState.hasOwnProperty(key as Key)) newerState[key as Key] = newState[key as Key]
}
return newerState;
}
How do I set up IncompleteVariant<T>
? I have tried:
/**
* Generic of object T but with all properties as optional.
*/
export type IncompleteVariant<T> = NonNullable<Partial<T>>
but am getting Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'. Type 'undefined' is not assignable to type 'T[keyof T]'.ts(2322)
CodePudding user response:
here is a working version :
export function orInitialState<T extends object> (newState: Partial<T>, initialState: T): T {
type Key = keyof T;
if (!newState) return initialState;
const newerState: T = { ...initialState };
for (const key of Object.keys(initialState)) {
if (newState.hasOwnProperty(key as Key)) {
const nskv = newState[key as Key];
if (nskv !== undefined && nskv !== null) {
newerState[key as Key] = nskv;
}
}
}
return newerState;
}
The mistake isn't on the InvariantType<T>
(wich has no point to be NonNullable <>
as T extends object).
You could not assume that newState.hasOwnProperty(key as Key) implies newState[key as Key] !== null | undefined
.
Example : { a: undefined }.hasOwnProperty("a")
is true
but { a: undefined }["a"]
is obviously undefined
.
The same applies with null
instead of undefined
.
Edit :
If you have concerns about these "undefined vs non-existant properties", you should read about this compiler option : https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes