You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
typeExtractStringType<T>=Textends `${infer U}` ? U : never;typeStrType1=ExtractStringType<'ABC'>;// 'ABC'typeStrType2=ExtractStringType<string>;// nevertypeStrType3=ExtractStringType<123>;// never
typeExtractArrayElementType<Textendsreadonlyany[]>=Textendsreadonly(infer U)[] ? U : never;// handles *array or tuple*, restricts input typestypeNumArrayType=ExtractArrayElementType<readonlynumber[]>;// numbertypeNumArrayType2=ExtractArrayElementType<[1,2,3]>;// 3 | 1 | 2typeNumArrayType3=ExtractArrayElementType<'ABC'>;// compiler errortypeFlatten<Type>=TypeextendsReadonlyArray<infer Item> ? Item : never;// handles only arraystypeFlatten2<Type>=Typeextendsreadonly(infer U)[] ? U : never;// handles *array or tuple*typeFlattenType=Flatten<number[]>;// numbertypeFlattenType1=Flatten<number[][]>;// number[]typeFlattenType2=Flatten2<readonlynumber[]>;// numbertypeFlattenType3=Flatten<'ABC'>;// no compiler errortypeFlattenType4=Flatten2<'ABC'>;// no compiler errortypeFlattenRecursive<T>=TextendsArray<infer U> ? FlattenRecursive<U> : T;typeFlattenRecursiveType=FlattenRecursive<number[]>;// numbertypeFlattenRecursiveType2=FlattenRecursive<number[][]>;// number
Extracting types from tuples
typeTupleToUnion<Textendsany[]>=Textends[infer U, ...infer Rest]
? U|TupleToUnion<Rest>
: never;functiongetTupleHead<Textendsany[]>(tuple: [...T]): TupleToUnion<T>{returntuple[0];}constresult1=getTupleHead(["hello",42]);// result1 is inferred as string | numberconstresult2=getTupleHead([true,false,true]);// result2 is inferred as booleantyperesult3=TupleToUnion<["hello",42,false]>;
More Complex Examples:
// Type to extract the part before the underscoretypeExtractPrefix<T>=Textends `${infer Prefix}_suffix` ? Prefix : never;// Test casestypeExample1=ExtractPrefix<"user_id_suffix">;// "user_id"typeExample2=ExtractPrefix<"admin_token_suffix">;// "admin_token"typeExample3=ExtractPrefix<string>;// nevertypeExample4=ExtractPrefix<number>;// never// Type to extract both protocol and domaintypeExtractProtocolAndDomain<T>=Textends `${infer Protocol}://${infer Domain}/` ? [Protocol,Domain] : never;// Test casestypeExample5=ExtractProtocolAndDomain<"https://example.com/">;// ["https", "example.com"]typeExample6=ExtractProtocolAndDomain<"ftp://my-server.org/">;// ["ftp", "my-server.org"]typeExample7=ExtractProtocolAndDomain<string>;// nevertypeExample8=ExtractProtocolAndDomain<number>;// never// DATEtypeExtractDateParts<T>=Textends `${infer Year}-${infer Month}-${infer Day}` ? [Year,Month,Day] : never;// Test casestypeDateParts1=ExtractDateParts<"2023-09-21">;// ["2023", "09", "21"]typeDateParts2=ExtractDateParts<"1990-01-01">;// ["1990", "01", "01"]typeInvalidDate=ExtractDateParts<string>;// never
functionmakeArray<Textendsunknown[]>(...args: T): T{returnargs;}constnumberArray=makeArray(1,2,3);// numberArray is inferred as `number[]`conststringArray=makeArray('a','b','c');// stringArray is inferred as `string[]`
Implicit infer for return value.
functiongetFirst<T>(arr: [T, ...any[]]): T{returnarr[0];}constfirstNumber=getFirst([1,2,3]);// firstNumber is inferred as numberconstfirstString=getFirst(['a','b','c']);// firstString is inferred as string
Functional interface + infer.
interfaceMapper<T,U>{(input: T): U;}typeMapArray<T,U>={mapArray: <VextendsArray<T>>(arr: V,fn: Mapper<T,U>)=>Array<U>;};constmapObjectsImplementation: MapArray<{id: string},string>={mapArray: (arr,fn)=>arr.map(obj=>fn(obj)),};constresult=mapObjectsImplementation.mapArray([{id: "1"},{id: "2"}],obj=>obj.id);// result is inferred as string[]