Тип объекта иногда не распознается

У меня есть следующий код TypeScript в VS Code:

const f1 = ():string => { return "abc"; }

const d:any = {}
d.f2 = ():string => { return "abc"; }

Наводишь мышку на f1, пишет const f1: () => string.

Наводишь мышку на f2, пишет any.

Разве f2 не должна также быть функцией, возвращающей строку?

Ни в том, ни в другом случае возвращаемый тип функции не является функцией; возвращаемый тип f1 — строка. Но тип любого реквизита на чем-то набранном any тоже будет any — вот что означает any.

jonrsharpe 22.12.2020 16:50

Заголовок следует отредактировать, так как мы не говорим о возвращаемых типах. Может быть, «Компилятор забывает тип после присваивания?» или что-то? Проблема здесь заключается в сочетании «назначения переменных, аннотированных несоюзным типом, не сужают тип переменной» и «any заразен».

jcalz 22.12.2020 16:54
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
2
431
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Нет, потому что объект, содержащий его, имеет тип 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. Мы можем присвоить barfoo, потому что 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

Площадка ссылка на код

Другие вопросы по теме