Typescript conditional types

Created By: chatGPT

In TypeScript, conditional types enable you to create types based on conditions, making your code more flexible and reusable. A conditional type uses the syntax A extends B ? C : D, where if type A is assignable to type B, the type resolves to C; otherwise, it resolves to D.
type IsString<T> = T extends string ? 'Yes' : 'No';
Here’s an example where we define a type IsString that checks if a given type T is a string. If it is a string, it resolves to 'Yes', otherwise, it resolves to 'No'.
type Check1 = IsString<string>;  // 'Yes'
type Check2 = IsString<number>;  // 'No'
You can also use conditional types with generic types to create more powerful constructs. For instance, you can infer types using the infer keyword within a conditional type.
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
In this example, ReturnType checks if T is a function type. If so, it infers the return type R; otherwise, it resolves to never. This can be particularly useful when writing utility types.
type Func = (x: number) => string;
type Test = ReturnType<Func>;  // string
You can also use conditional types for mapping over keys. For instance, you could create a type that transforms all keys of an object type based on their type.
type Nullable<T> = { [K in keyof T]: T[K] | null };
The Nullable type takes an object type T and constructs a new object type where all the properties are of types T[K] | null. This way, each property can be either its original type or null.
type Example = { name: string; age: number; };
type NullableExample = Nullable<Example>;
// { name: string | null; age: number | null; }
Another interesting use case is using conditional types for extracting properties of specific types from an object type.
type FilterType<T, U> = {
  [K in keyof T]-?: T[K] extends U ? K : never;
}[keyof T];
This FilterType utility type filters the keys of T that have a type assignable to U. The result is a union of the keys that satisfy the condition.
type Person = { id: number; name: string; active: boolean; };
type StringKeys = FilterType<Person, string>;  // 'name'
Introduction And SetupVariablesData TypesAnyUnknownVoidNeverStringNumberBooleanArrayTupleEnumObjectInterfaceType AliasMethodsFunctionArrow FunctionReturn TypeParametersDefault ParametersOptional ParametersRest ParametersControl FlowIf StatementElse StatementSwitch StatementFor LoopWhile LoopDo While LoopFor...of LoopFor...in LoopBreak StatementContinue StatementFunctionsFunction OverloadingRecursive FunctionExpression FunctionOperatorsArithmetic OperatorsAssignment OperatorsComparison OperatorsLogical OperatorsBitwise OperatorsConditional (ternary) OperatorData StructuresArrayTupleObjectMapSetCommentsSingle Line CommentMulti Line CommentSyntaxType AnnotationsType InferenceNamespaceModuleExportImportDecoratorsAmbient DeclarationsEvent HandlingEvent ListenersAddEventListenerRemoveEventListenerError HandlingTry...catch StatementThrow StatementFinally BlockCustom Error TypesAsync AwaitPromisesGenericsConditional TypesMapped TypesIntersection TypesUnion TypesLiteral TypesDiscriminated UnionsType GuardsTypeof GuardInstanceof GuardAssertion FunctionsModule Augmentation