Keyof, which is also type T

Is there a way to restrict keyof Tit to accept only keys of a certain type? Assume the following:

interface Something {
    id: number;  
    name: string;  
    value1: FancyType;  
    value2: FancyType;  
    value3: FancyType;
}

function someFunction(key: keyof Something) {
   // do something to a FancyType
}

someFunctionwill accept id | name | value1 | value2 | value3, is there a way to limit it to type keys FancyType, that is value1 | value2 | value3?

+7
source share
2 answers

Since TypeScript 2.8 is possible with conditional types ( Code ).

type FancyProperties<T> = Pick<T, { 
    [K in keyof T]: T[K] extends FancyType ? K : never 
}[keyof T]>;


function someFunction(key: keyof FancyProperties<Something>) {
   // do something to a FancyType
}

someFunction("id"); // Error
someFunction("value2"); // OK
+6
source

Unfortunately, I do not have the TS 2.6.2 compiler, so I can’t double check if this works. And since this involves adding an existing type, this is not my favorite solution (a solution of 2.8 with conditional types proposed by @Motti is definitely a way to go).

, . , FancyType - merge . :

interface FancyType {
  '**fancyBrand**'?: never
}

, FancyType , **fancyBrand** never. , , FancyType .

. ValueOf<T> :

type ValueOf<T> = T[keyof T];

, ValueOf<{a: string, b: number}> string | number. Diff :

type Diff<T extends string, U extends string> = 
  ({ [K in T]: K } & { [K in U]: never } & { [k: string]: never })[T];

, Diff<'a'|'b'|'c', 'a'> 'b'|'c'.

, FancyKeys<T>, , T, FancyType:

type FancyKeys<T> = Diff<keyof T, ValueOf<
  { [K in keyof T]: (T[K] & { '**fancyBrand**': K })['**fancyBrand**'] }>>

FancyKeys<Something> 'value1'|'value2'|'value3':

function someFunction(key: FancyKeys<Something>) {
  // do something to a FancyType
}
someFunction("id"); // error
someFunction("value2"); // okay

FancyKeys<T> T , T, '**fancyBrand**', . FancyType '**fancyBrand**' never undefined. , ( '**fancyBrand**'), .

Something {id: 'id', name: 'name', value1: undefined, value2: undefined, value3: undefined}. ValueOf<T> , 'id'|'name'|undefined. - , Diff<keyof Something, U> 'value1'|'value2'|'value2'... , undefined Diff<>, . , **fancyBrand**, FancyType, , , ( , ).

, , yucky, , . , , . !

+2

Source: https://habr.com/ru/post/1696120/


All Articles