Búsqueda de sitios web

typescript - Argumento predeterminado que determina el tipo de método genérico


Definí un método genérico cuyo tipo genérico está determinado por uno de los argumentos:

myMethod<T>(param1: number, param2: T): T {
  return param2;
}

Ahora, me gustaría tener un valor predeterminado para el parámetro, y T entonces se determinaría por el tipo del valor predeterminado:

myMethod<T>(param1: number, param2: T = 'myDefaultString'): T {
  return param2;
}

Pero eso no compila, porque espera que "string" coincida con T en lugar de determinar que T es 'string'.

Una solución sería escribir:

myMethod<T>(param1: number, param2: T = <any>'myDefaultString'): T {
  return param2;
}

Pero entonces necesito especificar el tipo explícitamente en el sitio de llamada:

const val: string = this.myMethod<string>();

Otra solución que consideré fue escribir una segunda función, sin el argumento por defecto:

myMethod<T>(param1: number, param2: T): T {
  return param2;
}

myMethodDefault(param1: number): string {
  return myMethod(param1, 'myDefaultString');
}

Pero entonces necesito un nombre diferente para ello, y eso me molesta.

¿Hay una mejor manera de hacer esto?

Respuesta #1

La parte del tipo puede cumplirse con un parámetro de tipo genérico por defecto (desde TypeScript 2.3):

class Hey {
    myMethod<T = string>(arg1: number, arg2?: T): T {
        if (arg2 === undefined)
            // have to handle default parameter manually
            return "myDefaultString" as any as T;
        return arg2;
    }
}

const h = new Hey();

// n1: string;
const n1 = h.myMethod(1);
// n2: typeof "mm"
const n2 = h.myMethod(2, "mm");
// n3: { a: number }
const n3 = h.myMethod(3, { a: 1 });

Respuesta #2

myMethod<T>(param1: number, param2: T = 'myDefaultString'): T {
  return param2;
}

El código anterior es efectivamente inválido, porque la expresión inst.myMethod<number>(23) tendría el tipo number, mientras que en tiempo de ejecución seguiría siendo un string.

Puedes evitar esto usando sobrecargas de firma:

// with only one param, the return type is a string:
myMethod(param1: number): string
// with two params, use a type parameter:
myMethod<T>(param1: number, param2: T): T
myMethod(param1: number, param2: any = 'myDefaultString') {
  return param2;
}

Esta versión hace que inst.myMethod<number>(23) sea inválido, porque la firma con un parámetro de tipo requiere un segundo parámetro.