Home > Enterprise >  TS - Make this the generic type
TS - Make this the generic type

Time:10-11

Is it possible to make "this" the generic type of the object? So, I have a following structure:

const obj = {
  fn1: () => number,
  fn2: (arg: number) => string,
  fn3 (arg: string) => null
}

I want to type obj such that the functions params depend on each other:

export type Queries<T extends Q> = {
  fn: () => any
  decoder: (arg: ReturnType<T['fn']>) => any
  transformationFn: (args: ReturnType<T['decoder']>) => any
}

Where Q is

type Q = {
  fn: () => Promise<any>
  decoder: (...args: any[]) => any
  transformationFn: (...args: any[]) => any
}

now, if i use the following type signature:

const obj1: Queries

I would need to pass in a generic. But I can't pass in itself hence my question

CodePudding user response:

You're looking for type argument inference. To get that, I think you'll need a do-nothing function:

interface Queries<EncodedType, DecodedType, TransformedType> {
    fn: () => EncodedType;
    decoder: (arg: EncodedType) => DecodedType;
    transformationFn: (arg: DecodedType) => TransformedType;
};

function makeQueries<EncodedType, DecodedType, TransformedType>(queries: Queries<EncodedType, DecodedType, TransformedType>) {
    return queries;
}

// Works, because the types match
const good = makeQueries({
    fn: () => Math.floor(Math.random() * 10000),
    decoder: (arg: number) => String(arg),
    transformationFn: (arg: string) => null,
});

// Error as desired, because they don't match
const bad = makeQueries({
    fn: () => Math.floor(Math.random() * 10000),
    decoder: (arg: number) => arg,
    // ^−−− Type '(arg: number) => number' is not assignable to type '(arg: number) => string'.
    transformationFn: (arg: string) => null,
});

Playground link

CodePudding user response:

I'm not sure that is possible. But it's simpler and perhaps more idiomatic to use the relevant types as generic arguments directly:

export type Queries<FnReturnType, DecoderReturnType> = {
  fn: () => FnReturnType
  decoder: (arg: FnReturnType) => DecoderReturnType
  transformationFn: (args: DecoderReturnType) => any
}

Or even more idiomatically and easier to read, as an interface:

export interface Queries<FnReturnType, DecoderReturnType> {
  fn(): FnReturnType
  decoder(arg: FnReturnType): DecoderReturnType
  transformationFn(args: DecoderReturnType): any
}
  • Related