Эта проблема
Ниже приведен фрагмент кода React + TypeScript, который я только что написал (упрощенный, чтобы мы могли сосредоточиться на вызываемой им ошибке):
const Foo = ({className}) =>
<Popper className={className + " someCustomClassName"} />
Это вызывает следующую ошибку TypeScript:
TS7031: Binding element 'className' implicitly has 'any' type.
Я понимаю, что это означает, что я не объявлял явно тип для переменной className, поэтому она «неявно» имеет тип any, но я не понимаю, почему это проблема. Это кажется нелогичным - не должны any типы допускать… любые типы ??
В кроличью нору
Немного поискав в Интернете позже, я нашел список кодов ошибок для TypeScript в репозитории: https://github.com/Microsoft/TypeScript/blob/2.1/src/compiler/diagnosticMessages.json#L3072
Это показывает источник сообщения об ошибке:
"Binding element '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7031
},
… Не очень полезно, но всегда приятно находить что-то в источнике, а не тупые сообщения в блогах (например, этот)…
Итак, в чем проблема, компилятор TypeScript? Я знаю, я могу просто объявить тип для моей переменной className и двигаться дальше ... но я хочу понять, почему.
Исправление, но я все еще ничего не знаю
Так, например, это «решит» проблему:
const Foo = ({className}:{[key:string]:any}) =>
<div className={className + " someCustomClassName"} />
В этом фрагменте я явно объявил все ключи в объекте первого аргумента как string и все значения этого объекта как any. Итак, единственное различие, которое я могу сказать, заключается в том, что я явно объявляю any, а не неявно. Я до сих пор не знаю, почему это лучше, потому что TypeScript способен выводить типы, то есть мне не нужно писать const foo: number = 5, я могу просто писать const foo = 5, а TypeScript выводит (выводить как вывод из фактов или предпосылки »), что тип переменной foo number. В этом простом foo примере TypeScript использует самую простую версию вывода типов:
Этот вид вывода имеет место при инициализации переменных и членов, установке значений параметров по умолчанию и определении типов возвращаемых функций.
Когда переменная инициализируется, предполагается, что тип переменной foo будет number. Есть два других способа определения типов: наиболее распространенный тип и контекстный тип, но я не думаю, что они имеют отношение к теме этой публикации.
Вниз по кроличьей норе, Глава 2
Может быть полезно вкратце подумать об основной структуре и синтаксисе моего исходного фрагмента кода. Давайте посмотрим на это еще раз:
const Foo = ({className}) =>
<Popper className={className + " someCustomClassName"} />
Я использую деструктуризацию объекта (назначение деструктуризации AKA) для извлечения className из объекта первого аргумента. Более подробный способ написать это:
const Foo = (obj) => {
const className = obj.className
return <Popper className={className + " someCustomClassName"} />
}
Деструктуризация - это функция JavaScript (ECMAScript 2015), поэтому она также доступна в TypeScript.
В другом измерении…
Один из способов использования вывода типа здесь - установить значение по умолчанию для параметра className:
const Foo = ({className = 'someDefaultValue'}) =>
<Popper className={className + " someCustomClassName"} />
При этом используется вывод типа посредством улучшенной проверки литерала объекта деструктуризации (также здесь): Свойства со значениями по умолчанию в шаблоне привязки объекта становятся необязательными в литерале объекта. Итак, мы явно устанавливаем значение по умолчанию, равное string, а параметр className неявно определяется как string. К сожалению, в моем случае я не хочу определять значение по умолчанию, поэтому для меня это не сработает.
TL; DR; Нет Неявно Любой
Ответ на эту загадку - опция компилятора TypeScript--noImplicitAny:
Вызывает ошибку в выражениях и объявлениях с подразумеваемым типом
any.
Эта опция по умолчанию отключена, но у меня есть файл tsconfig.json (конфигурация TypeScript), о котором я забыл, который включает эту опцию;
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react"
},
"include": ["./src/**/*"]
}
Согласно BASARAT, это полезно, если вам нужна« высокая безопасность при объявлении аргументов функции в TypeScript».