Я хочу быстро объявить объект, в котором поля должны быть определенного типа (CSSProperties
в этом примере, но в конце я хочу универсальный тип).
Когда я использую индексированный тип (или Record
), TS ограничивает значения значений поля-члена правильным типом и выдает ошибки, если я неправильно определяю их содержимое. Но он теряет информацию о том, какие поля были определены, поэтому ссылка на неопределенное поле не приведет к ошибке компиляции, и вызывающая сторона просто получит undefined
.
export const simpleStyle = {
a: {
margin: 0,
},
b: {
margin: 0,
wibble: 'blah', // no compile error: BAD
},
}
const simpleA = simpleStyle.a;
// causes a compile error: GOOD
// const simpleB = simpleStyle.wibble;
export type CssStyles = { [index: string]: CSSProperties };
export const typedStyle: CssStyles = {
a: {
margin: 0,
},
b: {
margin: 0,
// causes a compile error : GOOD
// wibble: 'blah',
},
}
const typedA = typedStyle.a;
// does not cause a compile error
const typedB = typedStyle.wibble;
Как определить этот тип, чтобы Typescript считал ссылки на неопределенные индексы недействительными? Где «определено» определяется содержимым объекта, который я объявляю (я не хочу переопределять все поля в объединении и не хочу определять явный тип).
Если вы хотите применить и ввести и в то же время вывести более конкретный подтип, вам нужно использовать общую функцию.
function createStyles<K extends string>(
styles: Record<K, CSSProperties>
): Record<K, CSSProperties> {
return styles
}
В вашем случае вы хотите вывести ключи объекта, но вы хотите, чтобы значения были строго известным типом. Это означает, что вы фиксируете ключи как K
и используете их в качестве ключей для объекта, который принимает функция.
Это также использует тип утилиты Record
для сопряжения ключей со значениями в объекте.
Теперь это работает так, как вы ожидаете:
export const typedStyle = createStyles({
a: {
margin: 0,
},
b: {
margin: 0,
wibble: 'blah', // error
},
})
const typedA = typedStyle.a;
const typedB = typedStyle.wibble; // error
Наконец, я добавлю, что команда Typescript работает над новой функцией, чтобы сделать функцию необязательной через оператор satisfies
.
Это просто общая функция, ничего особенного в ней нет. Он существует во время выполнения и практически ничего не делает во время выполнения. Но команда машинописи работает над улучшением этого: github.com/microsoft/TypeScript/issues/47920
Спасибо! Кажется, у меня есть слепое пятно для этих функций «форсирования типов». Есть название техники? Знает ли TS, что эта функция существует только для связи с компилятором? (Значит, после успешной проверки типов он может просто встряхнуть вызов метода, поскольку он ничего не делает?)