in

Interfaces vs tipos en TypeScript

apple touch icon@2

Demostrar la capacidad de reescribir recursivamente tipos e interfaces de Literal de Objeto de forma recursiva y no miembros de clase / propiedades / funciones.

Además, cómo distinguir y escribir las diferencias de verificación y la solución al problema discutido anteriormente, cuando Record no funciona debido a interfaces y cosas así, puede solucionarlo. Esto permitiría simplificar lo siguiente potencialmente para los tipos de mangostas:
https://github.com/wesleyolis/mongooseRelationalTypes mongooseRelationalTypes, DeepPopulate, pobulate

Además, un montón de otros enfoques para hacer genéricos de tipo avanzado e inferencia de tipo y las peculiaridades que lo rodean para la velocidad, todos pequeños trucos para hacerlos bien a partir de muchos experimentos, de prueba y error.

Patio de juegos mecanografiado:
Haga clic aquí para ver todos los ejemplos en un campo de juego en vivo

    class TestC {
        constructor(public a: number, public b: string, private c: string) {
    
        }
    }
    
    class TestD implements Record<any, any> {
    
        constructor(public a: number, public b: string, private c: string) {
    
        }
    
        test() : number {
            return 1;
        }
    }
    
    type InterfaceA = {
         a: string,
        b: number,
        c: Date
        e: TestC,
        f: TestD,
        p: [number],
        neastedA: {
            d: string,
            e: number
            h: Date,
            j: TestC
            neastedB: {
                d: string,
                e: number
                h: Date,
                j: TestC
            }
        }
    }


    type TCheckClassResult = InterfaceA extends Record<any, unknown> ? 'Y': 'N' // Y

    const d = new Date();
    type TCheckClassResultClass = typeof d extends Record<any, unknown> ? 'Y': 'N'      // N

    const metaData = Symbol('metaData');
    type MetaDataSymbol = typeof metaData;

    // Allows us to not recuse into class type interfaces or traditional interfaces, in which properties and functions become optional.
    type MakeErrorStructure<T extends Record<any, any>> = {
        [K in keyof T] ?: (T[K] extends Record<any, unknown> ?         MakeErrorStructure<T[K]>: T[K] & Record<MetaDataSymbol, 'customField'>)
    }

    type MakeOptional<T extends Record<any, any>> = {
        [K in keyof T] ?: T[K] extends Record<any, unknown> ? MakeOptional<T[K]> : T[K]
    }

    type RRR = MakeOptional<InterfaceA>
    const res  = {} as RRR;

    const num = res.e!.a; // type == number
    const num2 = res.f!.test(); // type == number

Hacer recursivas formas recursivas o claves de formas específicas

    type MakeRecusive<Keys extends string, T> = {
        [K in Keys]: T & MakeRecusive<K, T>
      } & T
  
    type MakeRecusiveObectKeys<TKeys extends string, T> = {
        [K in keyof T]: K extends TKeys ? T[K] & MakeRecusive<K, T[K]>: T[K]
    }

Cómo aplicar restricciones de tipo, para tipos de registro, que pueden validar interfaces como discriminadores:

    type IRecordITypes = string | symbol | number;
    
    // Used for checking interface, because Record<'key', Value> excludeds interfaces
    type IRecord<TKey extends IRecordITypes, TValue> = {
        [K in TKey as `${K & string}`] : TValue
    } 


    // relaxies the valiation, older versions can't validate.
    // type IRecord<TKey extends IRecordITypes, TValue> = {
    //     [index: TKey] : TValue
    // } 

    
    type IRecordAnyValue<T extends Record<any,any>, TValue> = {
        [K in keyof T] : TValue
    }    

    interface AA {
        A : number,
        B : string
    }

    interface BB {
        A: number,
        D: Date
    }

    // This approach can also be used, for indefinitely recursive validation like a deep populate, which can't determine what validate beforehand.
    interface CheckRecConstraints<T extends IRecordAnyValue<T, number | string>> {
    }

    type ResA = CheckRecConstraints<AA> // valid

    type ResB = CheckRecConstraints<BB> // invalid

Alternative for checking keys:

    type IRecordKeyValue<T extends Record<any,any>, TKey extends IRecordITypes, TValue> = 
    {
        [K in keyof T] : (TKey & K) extends never ? never : TValue
    } 
    
    // This approach can also be used, for indefinitely recursive validation like a deep populate, which can't determine what validate beforehand.
    interface CheckRecConstraints<T extends IRecordKeyValue<T, number | string, number | string>> {
        A : T
    }

    type UUU = IRecordKeyValue<AA, string, string | number>

    type ResA = CheckRecConstraints<AA> // valid

    type ResB = CheckRecConstraints<BB> // invalid

Ejemplo de uso de Discriminadores, sin embargo, por velocidad, prefiero usar literalmente lo que define cada clave para Grabar y luego haber pasado para generar los valores mixtos porque usa menos memoria y ser más rápido que este enfoque.


    type EventShapes<TKind extends string> = IRecord<TKind, IRecordITypes> | (IRecord<TKind, IRecordITypes> & EventShapeArgs)

    type NonClassInstance = Record<any, unknown>
    type CheckIfClassInstance<TCheck, TY, TN> = TCheck extends NonClassInstance ? 'N' : 'Y'

    type EventEmitterConfig<TKind extends string = string, TEvents extends EventShapes<TKind> = EventShapes<TKind>, TNever = never> = {
        kind: TKind
        events: TEvents
        noEvent: TNever
    }

    type UnionDiscriminatorType<TKind extends string, T extends Record<TKind, any>> = T[TKind]

    type PickDiscriminatorType<TConfig extends EventEmitterConfig<any, any, any>,
        TKindValue extends string,
        TKind extends string = TConfig['kind'],        
        T extends Record<TKind, IRecordITypes> & ({} | EventShapeArgs) = TConfig['events'],
        TNever = TConfig['noEvent']> = 
            T[TKind] extends TKindValue 
            ? TNever
            : T extends IRecord<TKind, TKindValue>
                ? T extends EventShapeArgs
                    ? T['TArgs']
                    : [T]
                : TNever        

    type EventEmitterDConfig = EventEmitterConfig<'kind', {kind: string | symbol}, any>
    type EventEmitterDConfigKeys = EventEmitterConfig<any, any> // Overide the cached process of the keys.

    interface EventEmitter<TConfig extends EventEmitterConfig<any, any, any> = EventEmitterDConfig,
                TCacheEventKinds extends string = UnionDiscriminatorType<TConfig['kind'], TConfig['events']>
                > {
      on<TKey extends TCacheEventKinds, 
                    T extends Array<any> = PickDiscriminatorType<TConfig, TKey>>(
                        event: TKey, 
                        listener: (...args: T) => void): this;

     emit<TKey extends TCacheEventKinds>(event: TKey, args: PickDiscriminatorType<TConfig, TKey>): boolean;
    }

Ejemplo de uso:

    interface EventA {
        KindT:'KindTA'
        EventA: 'EventA'
    }

    interface EventB {
        KindT:'KindTB'
        EventB: 'EventB'
    }

    interface EventC {
        KindT:'KindTC'
        EventC: 'EventC'
    }

    interface EventArgs {
        KindT:1
        TArgs: [string, number]    
    }
    const test :EventEmitter<EventEmitterConfig<'KindT', EventA | EventB | EventC | EventArgs>>;

    test.on("KindTC",(a, pre) => {
        
    })

Mejor enfoque para discriminar tipos y elegir tipos de un mapa para el estrechamiento, lo que generalmente da como resultado un rendimiento más rápido y menos sobrecarga para la manipulación de tipos y permite un almacenamiento en caché mejorado. compare con el ejemplo anterior anterior.


    type IRecordKeyValue<T extends Record<any,any>, TKey extends IRecordITypes, TValue> = 
    {
        [K in keyof T] : (TKey & K) extends never ? never : TValue
    } 

    type IRecordKeyRecord<T extends Record<any,any>, TKey extends IRecordITypes> = 
    {
        [K in keyof T] : (TKey & K) extends never ? never : T[K] // need to figure out the constrint here for both interface and records.
    } 
    
    type EventEmitterConfig<TKey extends string | symbol | number, TValue, TMap extends IRecordKeyValue<TMap, TKey, TValue>> = {
        map: TMap
    }

    type PickKey<T extends Record<any,any>, TKey extends any> = (T[TKey] extends Array<any> ? T[TKey] : [T[TKey]]) & Array<never>

    type EventEmitterDConfig = EventEmitterConfig<string | symbol, any, any>


    interface TDEventEmitter<TConfig extends EventEmitterConfig<any, any, TConfig['map']> = EventEmitterDConfig,
        TMap = TConfig['map'],
        TCacheEventKinds = keyof TMap
    > {
        
        on<TKey extends TCacheEventKinds, T extends Array<any> = PickKey<TMap, TKey>>(event: TKey, 
            listener: (...args: T) => void): this;

        emit<TKey extends TCacheEventKinds, T extends Array<any> = PickKey<TMap, TKey>>(event: TKey, ...args: T): boolean;
    }
   
    type RecordToDiscriminateKindCache<TKindType extends string | symbol | number, TKindName extends TKindType, T extends IRecordKeyRecord<T, TKindType>> = {
        [K in keyof T] : (T[K] & Record<TKindName, K>)
    }

    type DiscriminateKindFromCache<T extends IRecordKeyRecord<T, any>> = T[keyof T]

Ejemplo de usos:

    
    interface EventA {
        KindT:'KindTA'
        EventA: 'EventA'
    }

    interface EventB {
        KindT:'KindTB'
        EventB: 'EventB'
    }

    interface EventC {
        KindT:'KindTC'
        EventC: 'EventC'
    }

    type EventArgs = [number, string]

    type Items = {
        KindTA : EventA,
        KindTB : EventB,
        KindTC : EventC
        //0 : EventArgs,
    }

    type DiscriminatorKindTypeUnionCache = RecordToDiscriminateKindCache<string 
    //| number,
    "KindGen", Items>;

    type CachedItemForSpeed = DiscriminatorKindTypeUnionCache['KindTB']

    type DiscriminatorKindTypeUnion = DiscriminateKindFromCache<DiscriminatorKindTypeUnionCache>;

    function example() {
        
        const test: DiscriminatorKindTypeUnion;
        switch(test.KindGen) {
            case 'KindTA':
                test.EventA
                break;
            case 'KindTB':
                test.EventB
                break;
            case 'KindTC':
                test.EventC

            case 0:
                test.toLocaleString

        }
    }


    type EmitterConfig = EventEmitterConfig<string 
    //| number
    , any, Items>;

    const EmitterInstance :TDEventEmitter<EmitterConfig>;

    EmitterInstance.on("KindTB",(a, b) => {
        
        a.

    })

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Computer Hierarchy

Programas de aplicación frente a programas del sistema

Qxnxzwp3Hn3r3KvtxoZcVF 1200 80

Cómo conseguir un carguero No Man’s Sky gratis