Как ограничить keyof T только строковыми ключами?

Я пытаюсь расширить существующий интерфейс:

type ColDef = { field: string; }

так что я ограничу значения полей только фактическими свойствами указанного типа:

interface TypeSafeColDef<T> extends ColDef {
   field: keyof T
}

но я получаю:

Интерфейс TypeSafeColDef неправильно расширяет интерфейс ColDef. Типы свойства «поле» несовместимы. Введите 'keyof TRow | undefined 'нельзя присвоить типу' строка | неопределенный'. Тип 'keyof TRow' не может быть назначен типу 'строка | неопределенный'. Введите строку | номер | символ 'не присваивается типу' строка | неопределенный'. Тип "номер" не может быть присвоен типу "строка | неопределенный'. Тип keyof TRow нельзя присвоить типу string. Введите строку | номер | символ 'не может быть присвоен типу' строка '. Тип 'number' не может быть присвоен типу 'string'

Я пробовал следовать ограничению, но безуспешно

type StringKey = { [key: string]: any }

interface TypeSageColDef<TRow extends StringKey>

person Liero    schedule 23.01.2020    source источник
comment
extends { [key: string]: any } по какой-то причине ведет себя так же, как extends object (не ограничивая ключи только string). Реальный вопрос: зачем вам extends ColDef? У вас есть еще недвижимость на реальном примере?   -  person Aleksey L.    schedule 23.01.2020
comment
Мне нужно расширить ColDef, потому что я хочу получить ошибку компилятора при передаче недопустимого поля. Я не владею ColDef, это определение стороннего типа.   -  person Liero    schedule 23.01.2020


Ответы (1)


Ваш последний вариант довольно близок, нам все еще нужно расширить ColDef и извлечь string тип ключа для field:

type ColDef = { field: string; }

interface TypeSafeColDef<T extends object> extends ColDef {
  field: Extract<keyof T, string>
}

// test
type T1 = TypeSafeColDef<{ a: string }> // { field: "a"; }

field теперь имеет тип Extract<keyof T, string>, поскольку keyof поддерживает string | number | symbol имена свойств , поскольку TS 2.9. Существует параметр компилятора --keyofStringsOnly для отключения этого нового поведения, если вы не Не хочу этого.

Вторая альтернатива - определить псевдоним типа, чтобы избавиться от Extract. Это работает из-за того, что оператор пересечения никогда не вызывает ошибок:

type TypeSafeColDefAlias<T extends object> = ColDef & {
  field: keyof T
}

Пример кода

person ford04    schedule 23.01.2020
comment
extends StringKey выглядит лишним, если вы все равно делаете Extract<keyof T, string> - person Aleksey L.; 23.01.2020
comment
да, StringKey в этом случае не нужен. Предлагаю отредактировать ответ и я его принимаю - person Liero; 23.01.2020
comment
@Liero обновил ответ (и дал еще одну возможную альтернативу) - person ford04; 23.01.2020