Búsqueda de sitios web

typescript - Tipos genéricos en funciones de orden superior


Me gustaría usar un tipo genérico como parámetro en la función interna de una función de orden superior. Sin embargo, cuando hago esto, los parámetros de la función externa pierden sus tipos (se convierten en any).

Aquí hay un ejemplo de lo que estoy tratando de hacer. Espero recibir un error en la línea 2.

type TestFunc = <T>(outerArg: string) => (innerArg: T) => number
const test: TestFunc = <T>(outerArg) => (innerArg: T) => innerArg ? outerArg * 3 : 0 // no error because `outerArg` is `any` (unexpected)

Cuando innerArg no es genérico, obtengo el error que espero:

type TestFunc = (outerArg: string) => (innerArg: boolean) => number
const test: TestFunc = (outerArg) => (innerArg: boolean) => innerArg ? outerArg * 3 : 0 // error because `outerArg` is `string` (expected)

Pregunta

En la línea 2 del primer ejemplo, outerArg tiene tipo any. En la línea 2 del segundo ejemplo, outerArg tiene tipo string. ¿Por qué son diferentes?

Más detalles

Mi objetivo es permitir que T se especifique al evaluar la función externa. Por ejemplo:

type TestFunc = <T>(outerArg: string) => (innerArg: T) => number
const test: TestFunc = (outerArg) => (innerArg) => innerArg ? outerArg.length * 3 : 0 
const test2: TestFunc = <T>(outerArg) => (innerArg: T) => innerArg ? outerArg * 3 : 0 // want error


const fourBool = test<boolean>('str')
console.log(fourBool(true))
console.log(fourBool(1)) // want error

const fourNum = test<number>('str')
console.log(fourNum(true)) // want error
console.log(fourNum(1))

Aquí está en el playground de TypeScript.

Respuesta #1

Tienes dos funciones:

1) Una función con un tipo genérico que devuelve un número,

2) y una función que toma un número y devuelve un genérico.

Como mencionaste en los comentarios, estás usando una función flecha con un parámetro de tipo, pero eso no funcionará para ambas funciones. Puedes declarar tu función interna como genérica, y tu función externa con un parámetro de tipo:

type InnerFunc<T> = (inner: T) => number;
type TestFunc = <T>(outer: number) => InnerFunc<T>;

const test: TestFunc = <T>(outerArg: number) => (innerArg: T) => innerArg ? outerArg * 3 : 0;

const fourBool = test<boolean>(4);
fourBool(true); // OK
fourBool(1);    // error

Respuesta #2

Parece que esto podría ser un error en el compilador o estar diseñado así.

Pero esto podría funcionar como una solución temporal por ahora, donde adjuntas el tipo genérico a la función que usa el tipo genérico.

type TestFunc = (outerArg: string) => <T>(innerArg: T) => number

Está bien, esta es la manera en que querrías abordarlo para hacer lo que quieres:

type TestFunc = (arg1: string) => <T>(a: T) => number
type Number1 = (a: number) => number
const test: TestFunc = (arg1) => (a) => a ? (arg1 ? 1 : 2) : 0
const num1: Number1 = test("blah")
// OR
const newNum1 = <Number1>test("bleh")

Lo anterior te dará el error si colocas arg1 como lo hiciste antes y te dará la forma genérica que querías antes. Notarás que si defines el "subtipo" incorrectamente también dará un error de compilación.

Para mayor completitud, aquí hay una solución más simple (prácticamente lo que cdbajorin hizo en su solución):

type TestFunc1 = <T>(arg1: string) => (a: T) => number
const test1: TestFunc1 = (arg1: string) => a => a ? (arg1 ? 1 : 2) : 0
const newNum2 = test1<number>("bluh")

Artículos relacionados