С параметром --strictFunctionTypes
компилятора< /a>, параметры типа функции проверяются контравариантно. «Контравариант» означает, что отношение подтипа функции изменяется в направлении, противоположном отношению параметров функции. Так что если A extends B
, то (x: B)=>void extends (x: A)=>void
а не наоборот.
Это проблема безопасности типов из-за природы «заменяемости» в TypeScript, также известной как поведенческий подтип а>. Если A extends B
истинно, вы сможете использовать A
как B
. Если не можете, то A extends B
неверно.
Если вы отключите --strict
, компилятор будет использовать поведение до TS-2.6 для проверки параметров функции бивариантно, что небезопасно, но разрешено из соображений производительности. Это может быть не по теме здесь, но вы можете прочитать больше об этом в разделе FAQ по TypeScript для "Почему параметры функции бивариантны?"
В любом случае, если вам нужен тип функции, который принимает любое количество параметров unknown
, вы не можете безопасно использовать функцию, которая имеет только определенный подтип unknown
. Наблюдать:
const t: testArgsF = (b, s) => (b ? s.trim() : s).length
const u: unknownArgsF = t; // error!
u(1, 2, 3); // explosion at runtime! s.trim is not a function
Если бы testArgsF extends unknownArgsF
было истинным, то вы могли бы присвоить t
указанному выше u
без ошибок, что немедленно привело бы к ошибкам времени выполнения, когда u
счастливо принимает аргумент, отличный от string
секунды.
Вы видите, что единственный безопасный способ создать подтип/реализовать тип функции — это принять аргументы, которые являются такими же или более широкими, чем те, которые ожидаются супертипом/сигнатурой вызова. Вот почему --strictFunctionTypes
был введен в язык.
Если вы измените unknown
на any
(используя anyArgsF
вместо unknownArgsF
), то компилятор не будет жаловаться, потому что any
намеренно неправильный в TypeScript. Тип any
считается назначаемым как в, так и из любого другого типа; это небезопасно, потому что, например, string extends any
и any extends number
оба истинны, а string extends number
ложны. Таким образом, описанный выше принцип замещения не применяется, когда используется any
. Аннотирование значения как типа any
эквивалентно ослаблению или отключению проверки типа для этого значения. Это не спасет вас от ошибки времени выполнения; он просто заглушает ошибку компилятора:
const a: anyArgsF = t; // okay, type checking with any is disabled/loosened
a(1, 2, 3); // same explosion at runtime!
В случае, когда testNoArgsF extends unknownArgsF
истинно, это также является следствием взаимозаменяемости. Вы можете использовать функцию, которая не принимает аргументов, как если бы это была функция любого типа, поскольку она (обычно) в конечном итоге игнорирует любые переданные ей аргументы:
const n: testNoArgsF = () => 1;
const u2: unknownArgsF = n; // okay
u2(1, 2, 3); // okay at runtime, since `n` ignores its arguments
Это объясняется в записи FAQ по TypeScript "Почему функции с меньшим количеством параметров можно назначать функциям, которые принимают больше параметров?".
Хорошо, надеюсь, это поможет; удачи!
Playground link to code
person
jcalz
schedule
01.06.2020