Как создать целевой объект из общих частей в TypeScript?

Я использую [email protected].

У меня есть целевой объект:

interface MyTarget {
    a: string;
    b: string;
    c: string;
    d: string;
}

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

Одно такое преобразование может выглядеть так:

const convert = <T extends object>(t: T): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...t,
    };
};

Тем не менее, это приводит к:

error TS2698: Spread types may only be created from object types.

даже при том, что я защищаю общий T как object.

Затем я вспомнил, что есть тип Partial, поэтому я попробовал это:

const convert = (partial: Partial<MyTarget>): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...partial,
    };
};

Однако Partial делает все свойства необязательными. Я не хочу этого, и теперь он выкинет:

src/Partial.ts(14,5): error TS2322: Type '{ a?: string; b?: string; c: string; d: string; }' is not assignable to type 'MyTarget'.
  Property 'a' is optional in type '{ a?: string; b?: string; c: string; d: string; }' but required in type 'MyTarget'.

Я хочу создать экземпляр MyTarget с каждым полем, установленным как требование. Я хочу сохранить безопасность типов, поэтому я не хочу этого, хотя это работает:

const convert = (partial: Partial<MyTarget>): MyTarget => {
    return {
        c: "c",
        d: "d",
        ...partial,
    } as MyTarget; // loses type checks, really don't want to
};
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой 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 для повышения производительности приложения путем загрузки модулей только тогда, когда они...
4
0
2 989
2

Ответы 2

Я думаю, что вы используете более старую версию TS (в более новой версии спред-выражения печатаются правильно).

Независимо от этого, истинная проблема заключается в том, что литерал объекта может не быть полным MyTarget. Ваш код разрешит этот вызов

convert({a : "" })// return value is not really MyTarget since it will not contain b

Что вам действительно нужно, так это параметр MyTarget, кроме c и d:

interface MyTarget {
    a: string;
    b: string;
    c: string;
    d: string;
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
const convert = (t: Omit<MyTarget, 'c' | 'd'>) : MyTarget => {
    return {
        c: "c",
        d: "d",
        ...t,
    };
};

Красиво, жаль, что Exclude существует только с версии 2.8. В настоящее время я не в состоянии обновиться.

k0pernikus 05.02.2019 12:23

@k0pernikus k0pernikus Мм ... так действительно, очень старый (то есть 1 год +), я верю, что есть версия Omit для более старых версий. На какой именно версии вы находитесь?

Titian Cernicova-Dragomir 05.02.2019 12:25

@k0pernikus вот версия Omit для более старых версий, должна быть заменой, но я не проверял: Ideasintosoftware.com/typescript-advanced-tricks

Titian Cernicova-Dragomir 05.02.2019 12:26

Связанный тип Omit ведет себя не так, как я ожидал: stackoverflow.com/questions/54535539/…

k0pernikus 05.02.2019 14:28

Указанный здесь подход typeof отлично работает: stackoverflow.com/a/48215951/457268

k0pernikus 05.02.2019 16:50

@k0pernikus творческое решение, если вы не возражаете против дополнительных вещей во время выполнения, просто чтобы получить тип. Думаю, я слишком избалован сопоставленными и условными типами :)

Titian Cernicova-Dragomir 05.02.2019 16:52

Мы все еще используем версию 2.3 для этого проекта, так что нет: я вообще не возражаю против дополнительных вещей во время выполнения. Я принимаю влияние на производительность, чтобы иметь еще один аргумент в пользу будущего обновления;)

k0pernikus 05.02.2019 16:54

Я пошел с Решение Qwerti:

interface XYZ {
  x: number;
  y: number;
  z: number;
}

declare var { z, ...xy }: XYZ;

type XY = typeof xy; // { x: number; y: number;}

который отлично работает для [email protected].

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