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
