@Persotr27

Как создать универсальный условный тип в Typescript?

Всем привет!

Проблема следующая: Допустим, я хочу создать тип Creature со свойствами:
- type,
- subtype,
- params

И в случае, если я объвляю type = 'People', subtype должен иметь тип: 'adult' | 'child'.
Если же subtype = 'child', params должен быть {age: number; school: string;}
Если же subtype = 'adult', params должен иметь тип {height: number, weight: number, age: number}

Таким образом, хочу сделать type = 'animal', subtype = 'fish' | 'cat'. И в зависимости от subtype присвоить тип свойству params.

Зачем? Чтобы потом объявить, к примеру, массив creatures: Creature[], в котором напихать объектов одного типа, с разным свойством types.
Как это можно реализовать в TS'e, кроме обычного перечисления вот такой вот палочкой: "|".
Так же, буду благодарен за предложения, как это можно обойти, но при этом, чтобы сохранялся какой-то зависимый тайп чек.

Заранее спасибо!
  • Вопрос задан
  • 94 просмотра
Решения вопроса 2
bingo347
@bingo347 Куратор тега TypeScript
Crazy on performance...
Если type и subtype - строки, то можно так:
type CreatureBasis = {
    People: {
        child: {
            age: number;
            school: string;
        };
        adult: {
            age: number;
            height: number;
            weight: number;
        };
    };
    Animal: {
        fish: {
            waterBody: string;
        };
        cat: {
            catchMouses: boolean;
        };
    };
};
type Creature = {
    [K0 in keyof CreatureBasis]: {
        [K1 in keyof CreatureBasis[K0]]: {
            type: K0;
            subtype: K1;
            params: CreatureBasis[K0][K1];
        };
    }[keyof CreatureBasis[K0]];
}[keyof CreatureBasis];

https://www.typescriptlang.org/play?#code/C4TwDgpg...
TypeScript создавался чтоб затипизировать любую дичь, которую можно встретить в динамическом мире JavaScript. Как следствие у него тьюринг полная система типов, из чего есть 2 следствия:
1. при должном усердии можно затипизировать любую хотелку
2. некоторые особо навороченные типы могут повесить тайпчекер
Ответ написан
Комментировать
Aetae
@Aetae Куратор тега TypeScript
Тлен
Только через "палку", для того она и нужна:
interface CreatureBase {
  type: string;
  subtype: string;
  params: unknown;
}

interface PeopleBase extends CreatureBase {
  type: 'People';
}

interface PeopleChild extends PeopleBase {
  subtype: 'child';
  params: {
    age: number;
    school: string;
  }
}

interface PeopleAdult extends PeopleBase {
  subtype: 'adult';
  params: {
    height: number,
    weight: number,
    age: number
  }
}

type Creature = PeopleChild | PeopleAdult; //...

const arr: Creature[] = [
  {
    type: 'People',
    subtype: 'adult',
    params: {
      height: 1,
      weight: 2,
      age: 3
    }
  },
  {
    type: 'People',
    subtype: 'child',
    params: {
      school: 'foo',
      age: 3
    }
  },
  {
    type: 'People',
    subtype: 'adult',
    params: {
      school: 'foo', // err
      age: 3
    }
  }
]


А обойти типизацию можно кастанув as any, или дважды кастанув в новый тип var as unknown as type. Но не нужно.)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы