在为商店等字典编写接口时,我想区分商店中的数据模型和项目,即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
属性,否则T
与Item<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
答案 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