如何在TypeScript中定义可以具有除特定属性以外的任何属性的类型?

时间:2018-12-24 05:44:27

标签: typescript

在为商店等字典编写接口时,我想区分商店中的数据模型和项目,即ID和模型。我想添加一个约束,即模型本身在其界面中未使用字段id,但我不知道该怎么做。

type Item<T> = T & {id: string} 
// T is type of model
// Item<T> is type of objects in the store, use id as primary key

以下功能为简化版,用于在商店中添加新商品

function add<T>(model: Item<T>): T {
    const id = uuid();
    const result = {...model, id};
    store.push(result);
    return result;
}

最好在T上添加一些约束,使T不具有id属性,否则TItem<T>相同,同时{ id中的{1}}与Item<T>中的{1}不同,这会导致错误。

作为总结,我需要像这样的类型

T

我尝试了以下方法:

type Item<T extends "The type which allow any type without property id: string"> = T & {id : string}

它们都不起作用。

我想要类似的东西

type T0 = Exclude<any, {id: string}>; // any
type T1 = Exclude<{}, {id: string}>; // {}
type SafeModel<T extends Exclude<T, {id: string}>>; //circular constrain

或绕过圆形约束以定义类型的方法,该方法允许定义

type Model // define like this 
const v0: Model = {name: 'someName'} // ok
const v2: Model = {value: 123, id: 'someId'} //ok
const v1: Model = {name: 'someName', id: 'someId'} //error

2 个答案:

答案 0 :(得分:1)

使用never类型告诉TypeScript id不应该存在:

interface Unidentifiable extends Object {
    id?: never;
}

它将仅允许不具有称为id的属性的对象以及将id设置为undefined的对象。

将其用作对参数类型的约束:

type Item<T extends Unidentifiable> = T & { id: string };

用法:

interface Foo {
    age: number;
    name: string;
}

interface Bar {
    profession: string;
    id: string;
}

type T1 = Item<Foo> // OK
type T2 = Item<Bar> // Error

答案 1 :(得分:0)

打字稿大多使用结构化打字策略(与标称相反)。表达结构应具有而不是不具有的含义更容易。

这是一种通用类型,可以完成以下操作:

type XorExtend<T extends {
    [K in keyof T]: K extends keyof A
    ? A[K] extends T[K]
        ? never
        : T[K]
    : T[K]
}, A extends object,> = T & A

type a = XorExtend<{ id: string }, { a: 1 }> // okay
type b = XorExtend<{ id: string }, { id: 'asdf' }> // not okay!
type c = XorExtend<{ id: string }, { id: 1 }> // okay

游乐场here

假设您在某个地方使用了函数,那么您也可以利用此功能:

declare function xorExtend<O, P extends { [K in keyof P]: K extends keyof O
    ? O[K] extends P[K]
        ? never
        : P[K]
    : P[K]
}>(a: O, b: P): P & O


const test = xorExtend( { id: '' }, { b: '' } ) // ok, test: {id: ''} & {b: ''}
const test2 = xorExtend( { id: '' }, { id: 'whatever' } ) // not okay
const test3 = xorExtend( { id: '' }, { id: 4 } ) // okay

链接到游乐场here

希望这会有所帮助!

这是我在github上的要点:

https://gist.github.com/babakness/82eba31701195d9b68d4119a5c59fd35