给出以下类型:
export interface PatchOperation<T> {
from?: keyof T;
op: OperationType;
path: keyof T;
value?: T[keyof T];
}
interface Parent {
creation: Date;
id: number;
name: string;
}
如何强制PatchOperation<Parent>.value
具有PatchOperation<Parent>.path
的正确类型。
因此以下代码会产生错误:
const update: PatchOperation<Parent> = {
op: OperationType.Replace,
path: 'creation',
value: 'string', // Type 'string' is not assignable to type 'Date'.
};
答案 0 :(得分:1)
您可以使用distributive conditional type来改进您的解决方案,因此您无需显式传递键类型:
export type PatchOperation<T, K = keyof T> = K extends keyof T ? {
op: OperationType;
path: K;
value?: T[K];
} : never;
现在我们得到了预期的错误:
// Type 'string' is not assignable to type 'Date | undefined'
const update: PatchOperation<Parent> = {
op: OperationType.Replace,
path: 'creation',
value: 'string',
};
分布条件类型在实例化过程中自动分布在联合类型上
因此在我们的示例中,PatchOperation<Parent>
将等效于:
{
op: OperationType;
path: "creation";
value?: Date;
} | {
op: OperationType;
path: "id";
value?: number;
} | {
op: OperationType;
path: "name";
value?: string;
}
答案 1 :(得分:0)
不如我所希望的那样实用,但是它通过添加与属性名称相对应的第二个通用参数来起作用。
export interface PatchOperation<T, P extends keyof T> {
from?: keyof T;
op: OperationType;
path: keyof T;
value?: T[P];
}
interface Parent {
creation: Date;
id: number;
name: string;
}
const update: PatchOperation<Parent, 'creation'> = {
op: OperationType.Replace,
path: 'creation',
value: 'string', // Type 'string' is not assignable to type 'Date'.ts(2322)
};
const update: PatchOperation<Parent, 'creation'> = {
op: OperationType.Replace,
path: 'creation',
value: new Date(), // ok
};
实际用途:
type PatchDocument<T, P extends keyof T> = PatchOperation<T, P>[];
const update = createAction(
'[Project] Update Project',
props<{
operation : PatchDocument<ProjectDTO, keyof ProjectDTO>
}>()
);