Ограничение рекурсивного типа на значения свойств объекта - PullRequest
0 голосов
/ 24 мая 2018

Я пытаюсь ограничить типы свойств объекта рекурсивным способом.Конечная цель заключается в том, что свойства данного объекта должны быть number, string или другого вложенного объекта, который соответствует тому же описанию (свойства имеют тип number, string или далее вложенный)

В настоящее время я нашел единственный способ использовать подпись индекса.Как показано в этом примере кода на игровой площадке TypeScript , однако он не идеален, поскольку в класс необходимо поместить дополнительные строки, а также проблемы, с которыми это приводит в других местах в моей базе кода (это предотвращаетвведите вывод для правильной работы в определенных местах)

type AllowedTypes = string | number | ConstrainedClass;
type ConstrainedClass = { [key: string]: AllowedTypes };
class Test2 {
    [key: string]: AllowedTypes; // this line is needed
    public prop1: number;
}
class Test1 {
    [key: string]: AllowedTypes; // this line is needed
    public prop1: string;
    public prop2: number;
    public nestedProp: Test2;
}

function somefunction<T extends ConstrainedClass>(param: T) {
    return;
}

somefunction(new Test1());

Интересно, есть ли лучший способ сделать это?

1 Ответ

0 голосов
/ 24 мая 2018

Вы можете получить то, что вы хотите, используя сопоставленные условные типы и самодельные обобщенные типы (о которых я не могу найти хорошую документацию по TypeScript; но в Java * 1004 есть аналогичные варианты использования)* что может быть хорошо читает?).Давайте посмотрим:

type Constrained<T> = {
  [K in keyof T]: T[K] extends object ? Constrained<T[K]> : 
    T[K] extends string | number ? T[K] : never
}

A Constrained<T> принимает тип T и рекурсивно проходит через него, проверяя, является ли каждое свойство либо string, number, либо objectэто также соответствует Constrained.Любое свойство, которое ему не нравится, заменяется на never.

С этим вы можете создавать свои интерфейсы следующим образом:

interface Test extends Constrained<Test> {
    a: string; // okay
    b: number; // okay
    // c: boolean; // uncommenting this causes an error 
    d: { foo: string;  bar: string } // okay
}

Обратите внимание на самодельный универсальный шаблон, где объявлено, что Test расширяет Constrained<Test>.Это обеспечивает точное ограничение, которое вы хотите без подписей индекса.Если вы добавите свойство, которое не соответствует ограничению, оно выдаст вам ошибку, обычно что-то вроде Type 'XXX' is not assignable to type 'never'.

. Чтобы сделать это с классами, это будет выглядеть примерно так:

class Test2 implements Constrained<Test2> {
  public prop1: number = 1;
}
class Test1 implements Constrained<Test1> {
  public prop1: string = "a";
  public prop2: number = 1;
  public nestedProp: Test2 = new Test2();
}

(Я добавил инициализаторы, поскольку TypeScript теперь жалуется, когда вы не инициализируете экземпляры классов).И ваша функция работает так:

function someFunction<T extends Constrained<T>>(x: T) { }
someFunction(new Test1());

Надеюсь, это поможет.Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...