Текст, ссылающийся на общий T в теле функции

#typescript

Вопрос:

Если бы я должен был объявить тип как отдельную переменную, например:

 type Foo =  <T>(x: T) => T 
 

Затем используйте его для определения функции:

 const foo:Foo = x => {
  let a = /*...*/
  /*...function execution...*/
  return a
}
 

Как я могу ссылаться на универсальный тип T в теле функции, например, для объявления переменной a:T ?

Комментарии:

1. Я боюсь, что это может быть решением const foo:Foo = <T>(x: T) => { ... }

2. Поскольку T это не входит в область действия определения функции, вам придется объявить это снова в определении функции, как предлагает Нишант, или в противном случае вы можете написать typeof x вместо T .

Ответ №1:

Вы никак не можете ссылаться на этот аргумент типа, потому что он находится в объявлении типа. В основном это говорит о том, что «Видите ли, любая функция, имеющая тип Foo , является универсальной, вы можете передать аргумент типа любой функции этого типа, и ее возвращаемый тип и аргументы будут зависеть от этого аргумента типа». Этот аргумент типа T , указанный вами Foo , на самом деле никоим образом не существует, он просто служит для того, чтобы сообщить любому вызывающему абоненту Foo , что он может его принять.

Теперь вы используете этот аргумент при написании фактической реализации функции типа Foo . Нравится

 type Foo = <T>(x: T) => T

const foo: Foo = <T>(x: T) => {
    let a: T = x
    return a
}
 

Или, например, вы могли бы назвать его по-другому

 type Foo = <T>(x: T) => T

const foo: Foo = <U>(x: U) => {
    let a: U = x
    return a
}
 

Foo Тип ничего не навязывает, он просто говорит: «У этой функции есть 1 аргумент типа», и функция может вызывать и использовать этот аргумент, как ей заблагорассудится. Вы даже можете полностью игнорировать это

 type Foo = <T>(x: T) => T

const foo: Foo = () => {
  return 5 as any
}
 

Опять же, что касается вызывающей функции, foo она принимает один аргумент типа только потому foo , что является реализацией Foo типа, даже если foo на самом деле не использует его.

Или вы можете добавить дополнительный аргумент типа, который является необязательным, и необязательную переменную этого типа

 type Foo = <T>(x: T) => T

const foo: Foo = <U, K = number>(x: U, y?: K) => {
    if(y) console.log(y)

    let a: U = x
    return a
}
 

И это все еще справедливо, потому что любой, кто звонит foo , может посмотреть на определение типа и увидеть «Ок, Foo принимает 1 аргумент типа и 1 обычный аргумент». Если теперь они предоставляют 1 аргумент типа и 1 аргумент обычного типа, он все равно будет работать, потому foo что в таких условиях он работает нормально.

Ответ №2:

Просто назначьте/скопируйте/клонируйте x a :

 type Foo = <T>(x: T) => T

const foo: Foo = x => {
    let a = x
    /*...function execution...*/
    return a
}
 

Я пытался вывести универсальный тип:

 type Foo = <T>(x: T) => T

type ObtainGeneric<T extends (...args: any[]) => any> = T extends (u: infer U) => infer U1 ? U amp; U1 : never

const foo: Foo = x => {
    let a: ObtainGeneric<Foo> = null as ObtainGeneric<Foo>
    /*...function execution...*/
    return a
}

const result = foo(32)
 

Но безуспешно, потому что TS выводит T как unknown «потому T что», будет известно, что вывод можно сделать только тогда, когда smbd вызывает функцию

Я не думаю, что это возможно/безопасно сделать в области типов.

Комментарии:

1. Как это может помочь? Вопрос в том, чтобы ссылаться T не x на что .

2. @Clashsoft Поскольку x имеет тип T , переменная a также будет иметь тип T в этом коде. Вопрос в том , как объявить переменную типа T , что и делает этот код, поэтому он отвечает на вопрос.

3. How can I reference generic type T in the function body, such as to declare variable a:T ? — вторая часть предложения кажется мне примером. Другие люди могут наткнуться на этот вопрос с намерением сделать больше, чем просто объявить переменную с тем же типом, поэтому ответ не должен быть просто сосредоточен на примере, приведенном OP.

4. Вот почему ОП может просто проигнорировать мой ответ или понизить его