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

xia*_*x48 5 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
Run Code Online (Sandbox Code Playgroud)

以下函数是简化版,用于在商店中添加新商品

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

最好在没有属性的T情况下添加一些约束,否则会与 相同,同时in与 中的不一样,这会导致错误。TidTItem<T>idItem<T>T

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

type Item<T extends "The type which allow any type without property id: string"> = T & {id : string}
Run Code Online (Sandbox Code Playgroud)

我尝试过以下方法:

type T0 = Exclude<any, {id: string}>; // any
type T1 = Exclude<{}, {id: string}>; // {}
type SafeModel<T extends Exclude<T, {id: string}>>; //circular constrain
Run Code Online (Sandbox Code Playgroud)

它们都不起作用。

我想要一些类似的东西

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
Run Code Online (Sandbox Code Playgroud)

或者绕过循环约束来定义类型的方法,它允许定义

type Model<T> = T extends { id: string } ? never: T;
type Item<T extends Model<T>> = T & { id: string }
Run Code Online (Sandbox Code Playgroud)

Bab*_*ess 0

Typescript 主要使用结构化类型策略(而不是名义类型)。表达结构应该具有什么而不​​是不具有什么更容易。

这是完成类似操作的通用类型:

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
Run Code Online (Sandbox Code Playgroud)

游乐场在这里

假设您在某处使用某个函数,您也可以利用以下功能:

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
Run Code Online (Sandbox Code Playgroud)

此处链接到游乐场

希望这可以帮助!

这是我在 github 上的要点:

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