Возможно ли смешивать определенные типизированные ключи в типе TypeScript и типе универсального ключа?

Я пытаюсь создать тип для описания прокси-объекта ES6, где я буду знать типы для нескольких ключей, а остальные ключи будут общими с обратным вызовом в качестве значения, и я не буду знать их имена до времени выполнения .

Однако, если я попробую что-то вроде этого:

interface MyCallback {
  (): void;
}

interface MyType {
    myKey1: number;
    [key: string]: MyCallBack;
}

Я получаю такие ошибки, как:

[ts] Property 'myKey1' of type 'number' is not assignable to string index type 'MyCallback'.

Если я добавлю [key: string]: number, я получу ошибку Duplicate string index signature.

Если я перегружу его так, что будет похоже на number | MyCallback, я получу эту ошибку, если попытаюсь вызвать обратный вызов на экземпляре MyType:

[ts] Cannot invoke an expression whose type lacks a call signature. Type 'number | MyCallback' has no compatible call signatures.

Возможно ли иметь такой тип, который я пытаюсь создать в TypeScript?


person empyrical    schedule 21.05.2018    source источник
comment


Ответы (3)


ответ вроде как. Вы можете добиться этого с помощью типов пересечений:

interface MyType {
    myKey1: number;
}

interface MyCallBack {
    (): void;
}

interface GenericCallbackType {
    [key: string]: MyCallBack;
}

type CombinedType = MyType & GenericCallbackType;

const obj: CombinedType = {
    myKey1: 8,
    anyString: () => {}
}
person bryan60    schedule 21.05.2018
comment
Спасибо! Это сработает для меня, если я сделаю это типом пересечения, например type CombinedType = MyType & GenericCallbackType;. - person empyrical; 21.05.2018
comment
упс, на самом деле хотел поставить перекресток, мой плохой, хороший улов! - person bryan60; 21.05.2018
comment
Требуется ли для этого конкретная настройка? На 2.8.3 я получаю следующее: Property 'myKey1' is incompatible with index signature. Type 'number' is not assignable to type 'MyCallBack'. - person Clint; 21.05.2018
comment
@empyrical, не могли бы вы прокомментировать свою версию TS? Документы и проблемы с машинописным текстом говорят, что это не должно работать (и не работает в версии 2.8. .3). - person Clint; 22.05.2018
comment
Я использую версию 2.6.2 - другие версии еще не пробовал, но VS Code пока не жалуется. Я заметил, что один из комментаторов упоминает о проблемах с назначениями, но я просто получаю доступ и не нуждаюсь в назначении в моем варианте использования. - person empyrical; 22.05.2018
comment
у меня тоже не работает. этот ответ еще действителен? - person kundasaba; 16.04.2020
comment
В машинописном тексте 4.2.4 вы получите Type 'number' is not assignable to type 'MyCallBack'.ts(2322). - person kernel; 06.05.2021

Как отмечено в комментариях, принятый ответ не работает с заданиями, что приводит к ошибке Property 'myKey1' is incompatible with index signature. Для работы с заданиями мы можем использовать ответ @jcalz здесь:

interface MyCallback {
  (): void
}

interface MyType {
  myKey1: number
}

const asCombinedType = <C>(
  res: C & MyType & Record<Exclude<keyof C, keyof MyType>, MyCallback>
): C => res

const obj = asCombinedType({
  anyKey: () => { /* ...*/ },
  myKey1: 12
})

По общему признанию, немного запутанный, но он выполняет свою работу.

person Aleksi    schedule 17.03.2019

Принятый ответ не работал для меня, этот фрагмент кода работает: Ссылка на игровую площадку

interface MyType {
    myKey1: number;
}

interface GenericCallbackType {
    [key: string]: () => void;
}

type CombinedType = MyType | GenericCallbackType;

const obj: CombinedType = {
    myKey1: 8,
    anyString: () => {}
}
person kundasaba    schedule 22.04.2020