У меня есть следующий код TypeScript в VS Code:
const f1 = ():string => { return "abc"; }
const d:any = {}
d.f2 = ():string => { return "abc"; }
Наводишь мышку на f1
, пишет const f1: () => string
.
Наводишь мышку на f2
, пишет any
.
Разве f2
не должна также быть функцией, возвращающей строку?
Заголовок следует отредактировать, так как мы не говорим о возвращаемых типах. Может быть, «Компилятор забывает тип после присваивания?» или что-то? Проблема здесь заключается в сочетании «назначения переменных, аннотированных несоюзным типом, не сужают тип переменной» и «any
заразен».
Нет, потому что объект, содержащий его, имеет тип any
, поэтому Typescript не может сделать вывод, что он всегда будет функцией. Цель any
не в том, чтобы выдавать ошибки проверки типов. Если в этом случае он выводит тип функции, он также заблокирует вам присвоение значения с другим типом, что может быть нежелательным.
Когда значение имеет тип any, вы можете получить доступ к любым его свойствам (которые, в свою очередь, будут иметь тип any)
https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any
Если у вас несоюзный тип Foo
, например:
interface Foo {
a: string;
}
и если вы аннотируете переменную как этот тип:
let foo: Foo = { a: "hello" };
тогда любые последующие присвоения или изменения свойств не повлияют на видимый тип этой переменной. Например:
let bar = { a: "hello", b: "goodbye" };
bar.b; // okay
foo = bar; // okay, bar is assignable to Foo
foo.b // <-- error! Property 'b' does not exist on type 'Foo'
Здесь у нас есть значение bar
, о котором известно, что оно имеет свойство b
. Мы можем присвоить bar
foo
, потому что bar
является допустимым Foo
(у него есть свойство a
). Но как только мы выполним это присваивание, компилятор не изменит видимый тип foo
. Это все еще просто Foo
, и поэтому мы больше не можем читать из него свойство b
.
Примечание: для типов объединения это сложнее, потому что анализ потока управления (microsoft/TypeScript#8010) приводит к тому, что некоторые присваивания явно сужают тип переменной до некоторого подмножества членов объединения. Но, согласно комментарию в microsoft/TypeScript#8513, они не сделали этого для несоюзных типов.
Вы аннотировали d
как типа любого, который не является союзным типом. После этого любые назначенные вами свойства будут немедленно забыты.
Кроме того, тип any
— это выход из системы типов (см. этот ответ ). Он заразен и распространяется наружу на многие другие типы, к которым он прикасается: any | Foo
есть any
; any & Foo
есть any
; any["somePropKey"]
есть any
. Последнее, где вы ищете недвижимость и получаете any
, это то, что случилось с d.f2
. Это просто any
.
Если вы не хотите, чтобы это произошло, вам следует держаться подальше от any
и вместо этого использовать более сильные типы, предпочтительно более неизменяемые объекты, и позволить компилятору делать выводы вместо того, чтобы вручную аннотировать, где это возможно:
const d2 = {
f2: () => { return "abc" }
}
d2.f2().toUpperCase(); // okay
Ни в том, ни в другом случае возвращаемый тип функции не является функцией; возвращаемый тип
f1
— строка. Но тип любого реквизита на чем-то набранномany
тоже будетany
— вот что означаетany
.