Je vous partage quelques astuces que j'ai rassemblées au fil du temps à force de bloquer face à certains problèmes en TypeScript 😎

x is T

function isDefined<T>(x: T | undefined | null): x is T {
    return x !== null && typeof x !== 'undefined';
}
function isUndefined<T>(x: T | undefined | null): x is undefined {
    return x !== null && typeof x === 'undefined';
}
function isDefinedAndNotEmpty<T>(x: T | '' | undefined | null): x is T {
    return x !== null && typeof x !== 'undefined' && x !== '';
}


function foo(thing: { foo: string } | undefined) {
   if (isDefined(thing)) {
        console.log(thing.foo);
    } 
}
foo(undefined);

const thing2 = [1,2,3,undefined,null,5].filter(isDefined);

ReturnType<typeof fn>

function f(): string { return ''; }
const foo: ReturnType<f> = '';
    
const g = (): string => '';
const bar: ReturnType<g> = '';

function incrementCounter(counterName: string) {
    return { type: 'INCREMENT_COUNTER', counterName } as const;
}
type IncrementCounter = ReturnType<incrementCounter>;

Parameters<typeof fn>

function f(f1: string) {}
const foo1: Parameters<f> = [''];
const foo2: Parameters<f>[0] = '';
    
const g = (g1: string) => {};
const bar1: Parameters<g> = [''];
const bar2: Parameters<g>[0] = '';

import { superComplexFunction } from 'some-lib';
const param1: Parameters<superComplexFunction>[0] = {...};

DeepPartial

type Primitive = number | string | boolean | symbol | Date; type DeepPartial<T> = { [K in keyof T]?: T[K] extends Primitive ? T[K] : DeepPartial<T[K]> };

interface Thing {
    a: {
        b: {
            c: string;
            d: string;
        },
        e: string;
    },
    f: string;
}

const foo: DeepPartial<Thing> = {
    a: { b: { d: '' } }
}

Omit

interface Item {
    id: string;
    label: string;
    createdOn: Date;
}

function createItem(newItemWithoutId: Omit<Item, 'id'>): void {}
function createItem2(newItemWithoutId: Omit<Item, 'id' | 'createdOn'>): void {}

Required

interface Item {
    id?: string;
    label: string;
}

function editItem(itemWithIdRequired: Required<Item>): void {}

Type

class Foo {}
class Bar extends Foo {}
function f(clazz: Type<Foo>) {}

f(Foo);
f(Bar);

Si vous êtes dans un projet Angular, vous pouvez récupérer Type comme ça :

import { Type } from '@angular/core';

Sinon je vous donne la même définition :

interface Type<T> extends Function {   new (...args: any[]): T; }

Crédit photo : https://pixabay.com/photos/rubber-duck-bath-duck-toys-costume-1401225/