Home > database >  How do I define a generic object that can include any of only the properties of T?
How do I define a generic object that can include any of only the properties of T?

Time:01-13

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

  • Related