Typescript generics

Created By: chatGPT

TypeScript generics enable you to create reusable components and functions that can work with a variety of data types. This provides flexibility and type safety in your code, as you can define a placeholder type that gets replaced with a concrete type when the function or class is used. Below is a simple example of defining a generic function:
function identity<T>(arg: T): T {
    return arg;
}

const stringIdentity = identity<string>('Hello, World!');
const numberIdentity = identity<number>(42);
In the example above, <T> represents a type variable that can be replaced with any type. When you call the function, you can explicitly specify the type or let TypeScript infer it based on the argument provided.
const inferredIdentity = identity('TypeScript'); // Type is inferred as string
You can also create generic interfaces and classes to achieve similar results. Here’s how to define a generic interface:
interface GenericIdentityFn<T> {
    (arg: T): T;
}

const myIdentity: GenericIdentityFn<number> = function (arg) {
    return arg;
};
In this example, we defined an interface GenericIdentityFn that describes a function taking an argument of type T and returning the same type. This allows you to create multiple implementations for different types while adhering to the same contract.
const myStringIdentity: GenericIdentityFn<string> = function (arg) {
    return arg;
};
You can also create classes with generics. Below is an example of a generic class that represents a box containing a value of any type:
class Box<T> {
    private value: T;

    constructor(value: T) {
        this.value = value;
    }

    getValue(): T {
        return this.value;
    }
}

const numberBox = new Box<number>(123);
const stringBox = new Box<string>('TypeScript Generics');
In this class, Box<T> can hold any type of value while maintaining type safety. When you create an instance of Box, you specify the type so that the getValue method knows the return type correctly.
const retrievedNumber = numberBox.getValue(); // Type inferred as number
const retrievedString = stringBox.getValue(); // Type inferred as string
Constraints can also be applied to generics using extends. This allows you to limit the types that can be substituted for a generic type. Here is an example:
function loggingIdentity<T extends { length: number }>(arg: T): T {
    console.log(arg.length);  // Now we can use 'length'
    return arg;
}

loggingIdentity([1, 2, 3]); // Valid
loggingIdentity('Hello!'); // Valid
// loggingIdentity(3); // Error: number doesn't have a .length
In this case, the function loggingIdentity accepts any type T that has a length property. This adds yet another layer of type safety to your generics, ensuring that you can only operate on suitable types.
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