Make type with keys from union of strings
type Keys = 'foo' | 'bar' | 'baz'
type Obj = { [ key in Keys ] : any }
// {
// foo: any
// bar: any
// baz: any
// }
Make type from object and type from object keys
const obj = {
foo : 1 ,
bar : 'hello' ,
baz : true ,
}
type ObjType = typeof obj
// {
// foo: number
// bar: string
// baz: boolean
// }
type Keys = keyof ObjType
// or
type Keys = keyof typeof obj
// 'foo' | 'bar' | 'baz'
Make union of values from enum-like object
const roles = {
User : 'ROLE_USER' ,
Admin : 'ROLE_ADMIN' ,
} as const
type Roles = typeof roles
type RoleValues = Roles [ keyof Roles ]
// ''ROLE_USER' | 'ROLE_ADMIN'
type RecursivePartial < T > = {
[ P in keyof T ] ?:
T [ P ] extends ( infer U ) [ ] ? RecursivePartial < U > [ ] :
T [ P ] extends object ? RecursivePartial < T [ P ] > :
T [ P ] ;
} ;
function arrayToRecord < T extends { id : string } > ( obj : T [ ] ) : Record < string , T > {
return obj . reduce ( ( acc : { [ key :string ] : T } , cur ) => {
acc [ cur . id ] = cur
return acc
} , { } )
}
// usage
interface Obj {
id : string
foo : string
}
const objArr : Obj [ ] = [
{ id : '1' , foo : 'bar' } ,
{ id : '2' , foo : 'baz' }
]
const objRec = arrayToRecord ( objArr )
// Record<string, Obj>
type PickFromUnion < T , K > = Extract < T , { kind : K } > ;
// usage
type Foo = {
kind : 'foo'
prop : string
}
type Bar = {
kind : 'bar' ,
prop : number ;
}
type PickedBar = PickFromUnion < Foo | Bar , 'bar' >
// {
// kind: 'bar',
// prop: number;
// }
type FieldsOfType < S , T > = { [ K in keyof S ] : S [ K ] extends T ? K : never } [ keyof S ] ;
// usage
type Foo = {
bar : string ;
baz : number ;
xyz : string ;
}
type Bar = FieldsOfType < Foo , string >
// 'bar' | 'xyz'
type Brand < K , T > = K & { __brand : T } ;
type AppDate = Brand < string , 'AppDate' > ; // eg 25.12.2019
type ApiDate = Brand < string , 'ApiDate' > ; // eg 2019-12-25
// AppDate is not assignable to ApiDate
see Nominal typing in TS
// https://github.com/Microsoft/TypeScript/issues/14094#issuecomment-373782604
type Without < T , U > = { [ P in Exclude < keyof T , keyof U > ] ?: never } ;
type XOR < T , U > = ( T | U ) extends object
? ( Without < T , U > & U ) | ( Without < U , T > & T )
: T | U ;
// make one field optional
type PartialBy < T , K extends keyof T > = Omit < T , K > & Partial < Pick < T , K > >
Props dependent on other props (React)
Playground
function example
type Mask = string | ( ( ) => any ) ;
type Props < M extends Mask > = {
mask : M ;
unmask ?: boolean ;
} & ( M extends NumberConstructor ? { numberProp ?: string } : { } ) ;
function Comp < M extends Mask > ( props : Props < M > ) {
return < > hello < / >;
}
function TestComp ( ) {
return (
< >
< Comp mask = { Number } numberProp = 'bla' / > // ok
< Comp mask = { Number } numberProp = 'bla' wrongProp / > // err, unknown prop
< Comp mask = { Number } numberProp / > // err, numberProp wrong type
< Comp mask = { ( ) => false } numberProp / > // err, numberProp only for Number
< Comp mask = { 'some string' } numberProp / > // err, numberProp only for Number
< Comp mask = { 'some string' } / > // ok
< / >
)