Выведите тип объекта, используя схему (массив объектов)

Я пытаюсь определить типы объектов, используя схему. Эта схема представляет собой массив объектов, содержащий все свойства поля.

type Field = {
    name: string
    kind: 'string' | 'integer' | 'float' | 'bool'
    required?: boolean
}
type Schema = { fields: Field[] };

const schema: Schema = {
    fields: [
        { name: 'id', kind: 'integer', required: true },
        { name: 'name', kind: 'string', required: true },
        { name: 'debits', kind: 'float' },
    ]
}

const customer: Record<?> = {
  id: 1,
  name: 'John Doe',
  debits: 50
}

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

Он не разрешится в Field, поскольку вы передали ему буквальный объект без объявленного типа. Его тип буквально является этим объектом. Вам нужно дать некую подсказку или заставить это сделать с помощью утверждения типа.

Jeff Mercado 20.07.2024 07:27

• Вы не можете пометить schema как Schema, не выбросив при этом всю важную информацию. Вам нужно позволить TS сделать это и вместо этого написать const schema = ⋯ as const satisfies Schema. • Я предполагаю, что вас волнует required сделать свойство необязательным или нет, верно? Если required отсутствует или false то это необязательно? • Соответствует ли этот подход вашим потребностям? Если да, то я напишу ответ с объяснением; если нет, то что мне не хватает?

jcalz 20.07.2024 14:46
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
2
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете определить следующие типы. Не используйте T extends Schema в type SchemaToRecord<T>!

Если вы используете T extends Schema, вы скроете фактическое значение каждого Field. TypeScript выведет типы, используя тип Field.

Неиспользование T extends Schema означает, что вы задерживаете вывод о типе конкретного Field значения, предусмотренного T.

type Field = {
    kind: 'string' | 'integer' | 'float' | 'bool';
    required?: boolean;
};

type KindToType<T> =  T extends 'string' ? string: 
  T extends 'integer' ? number : 
  T extends 'float' ? number :
  T extends 'bool' ? boolean : never;

type GetMandatoryKeys<T> = {
  [P in keyof T]: T[P] extends Exclude<T[P], undefined> ? P : never
}[keyof T]

type UndefinedToOptional<T> = Partial<T> & Pick<T, GetMandatoryKeys<T>>

type SchemaToRecord<T> = UndefinedToOptional<{
  [K in keyof T]: 'required' extends keyof T[K] ?
    ('kind' extends keyof T[K] ? KindToType<T[K]['kind']> : never) :
    ('kind' extends keyof T[K] ? KindToType<T[K]['kind']> | undefined : never)
}>;

Вы можете использовать вышеуказанные типы следующим образом:

const customerSchema = {
  id: { kind: 'integer', required: true } as const,
  name: { kind: 'string', required: true } as const,
  debits: { kind: 'float' } as const,
}

type CustomerSchema = typeof customerSchema;
type CustomerRecord = SchemaToRecord<CustomerSchema>;

// OK
const customer: CustomerRecord = {
  id: 1,
  name: 'John Doe',
  debits: 50
}

// OK
const customer: CustomerRecord = { id: 1, name: 'John Doe', debits: 50 };

// OK
const customer: CustomerRecord = { id: 1, name: 'John Doe' };

// ERROR Type 'string' is not assignable to type 'number'
const customer2: CustomerRecord = { id: 1, name: 'John Doe', debits: '50' };

// ERROR Type 'number' is not assignable to type 'string'
const customer3: CustomerRecord = { id: 1, name: 50 };

Не используйте const customerSchema: Schema = {... в const customerSchema = {! вместо этого используйте as const (в каждом поле).

Если вы используете : Schema, TypeScript будет определять типы, используя Schema (тип), а не значение customerSchema. Это приведет к менее точному выводу типа.

Вы можете увидеть это в действии здесь

Я думаю, нам нужно услышать ОП, означает ли «нет required» необязательно. Если да, то customer3 следует разрешить, а не отвергнуть. И кстати, ссылка на вашу игровую площадку недействительна.

jcalz 21.07.2024 01:41

Думаю, я исправил ссылку, а также исправил другую проблему. Теперь обязательное неопределенное или ложное свойство означает, что свойство является необязательным.

Remo H. Jansen 21.07.2024 03:16

Это работает как шарм... Я реорганизую свой код, чтобы он соответствовал этому примеру... большое спасибо!.

Belizário Ribeiro 22.07.2024 03:03

Другие вопросы по теме