Когда вы определяете тип Bucket
с индексированной подписью ({ [x: <key type>] : <value type> }
), вы сообщаете компилятору, что нет прямой корреляции между конкретными элементами и их типами. Кроме того, any
не является типом заполнителя, он отключается проверки типов. Таким образом, компилятор показывает вам то, что вы ему сказали, а именно:
- все ключи
bucket
относятся к типу string
bucket
имеет значения типа Map<string, { data: any }
.
Затем вы назначаете объект переменной bucket
. На этом этапе значение проверяется на совместимость с предоставленным типом (Bucket
), и, поскольку вы отключили проверку типа для data
члена, any
все идет, поэтому ошибок нет.
Затем, когда вы get
значение члена bucket
, тип определяется как { data: any; } | undefined
, потому что нет гарантии, что "a"
или "b"
будут присутствовать в [x: string]
, следовательно, значение может быть undefined
. Мы уже говорили о том, почему data
не сужается.
Если вы удалите аннотацию типа из bucket
, вы заметите, что вывод резко улучшится, потому что теперь также выводится тип: { a: Map<any, any>; b: Map<string, { data: boolean; }>
. В то же время вы теряете проверку типов, какие элементы bucket
могут содержать.
Итак, что вы можете с этим поделать? Вам необходимо явно указать компилятору, какова взаимосвязь между определенными ключами и значениями. Создание общего Bucket
может помочь нам в этом:
type Bucket<T> = {
[ P in keyof T ]: Map<string, { data: T[P] }>
}
Теперь вы правильно вывели data
типов, уверенность в форме bucket
и автозаполнение за счет большей подробности, что является небольшой платой за эти преимущества (кроме того, вы можете сделать параметр типа интерфейсом или типом):
type Bucket<T> = {
[ P in keyof T ]: Map<string, { data: T[P] }>
}
const bucket: Bucket<{ a: number, b: boolean, c?: string }> = {
a:new Map(),
b:new Map(),
};
bucket.a.set('a', { data: 1 })
bucket.b.set('b', { data: 'b' }) // Type 'string' is not assignable to type 'boolean'
const getA = bucket.a.get('a') // data is number
const getB = bucket.b.get('b') // data is boolean
площадка
Функция идентификации, подобная упомянутой Алексеем Л., делает то же самое - удаляет явную аннотацию типа из bucket
, сохраняя при этом проверку типа (ограничение extends Bucket
) и возвращая буквальный тип (форма <T>(a:T) => T
). Он требует создания функции в скомпилированном коде, но позволяет вам определить тип bucket
.
person
Oleg Valter
schedule
11.02.2021
a
- person Aleksey L.   schedule 10.02.2021