typescript动态类型和泛型
我很难理解typescript动态(和泛型)类型 我试图实现的是创建一个函数,该函数返回一个具有特定类型的对象,其中该对象的某些属性必须匹配给定给该函数的任何参数 所以,基本上我想要发生什么(伪):typescript动态类型和泛型,typescript,typescript-generics,Typescript,Typescript Generics,我很难理解typescript动态(和泛型)类型 我试图实现的是创建一个函数,该函数返回一个具有特定类型的对象,其中该对象的某些属性必须匹配给定给该函数的任何参数 所以,基本上我想要发生什么(伪): const listRequest=createRequest('list',{id:[1,2]}) 此函数应按如下方式创建一个对象: { operationVersion: 1, protocolVersion: 2, operation: 'list', // first param
const listRequest=createRequest('list',{id:[1,2]})代码>
此函数应按如下方式创建一个对象:
{
operationVersion: 1,
protocolVersion: 2,
operation: 'list', // first param
list: { // prop name must match with first param
ids: [1, 2], // second param
}
}
目前,我的代码如下所示:
interface IBaseRequest {
operationId: number;
protocolVersion: number;
operation: string;
authenticationToken?: string;
}
export type BaseRequest<Operation extends string> = {
[Prop in keyof IBaseRequest]: IBaseRequest[Prop];
} & Record<Operation, any>;
type CreateRequestType = <T extends string>(operation: string, params: any) => BaseRequest<T>;
export const createRequest: CreateRequestType = <T extends string>(operation: string, params: any) => {
const req = {
operation: operation,
operationId: 1,
protocolVersion: 2,
};
req[operation] = params;
return req as BaseRequest<T>;
};
我得到一个错误:
Conversion of type 'BaseRequest<string>' to type '"list"' may be a mistake
because neither type sufficiently overlaps with the other. If this was
intentional, convert the expression to 'unknown' first.ts(2352)
将“BaseRequest”类型转换为“list”类型可能是错误的
因为两种类型都没有足够的重叠。如果这是
有意的,首先将表达式转换为“未知”。ts(2352)
有没有办法用类型和泛型来实现这一点?这样的函数很难用TypeScript编码。以下替代版本更简单、更简洁,只需一个“聚合”输入参数,在您的示例中,它将是{list:{a:'aa'}
function createRequestBis<K extends string, T>(payload: { [k in K]: T }) {
const operation = Object.keys(payload)[0] as K;
return Object.assign({
operationVersion: 1,
protocolVersion: 2,
operation,
}, payload);
}
const listRequest = createRequestBis({ list: { a: 'aa' } });
listRequest; // Type { operationVersion: number... } & { list: { a: string } } -> True but ugly!
listRequest.operation; // Type "list" -> OK
listRequest.list.a; // Type "string" -> OK
函数createRequestBis(有效负载:{[k in k]:T}){
常量操作=对象键(有效载荷)[0]作为K;
返回Object.assign({
操作版本:1,
协议版本:2,
活动
},有效载荷);
}
const listRequest=createRequestBis({list:{a:'aa'}});
listRequest;//键入{operationVersion:number…}&{list:{a:string}}->True但丑陋!
listRequest.operation;//键入“列表”->OK
listRequest.list.a;//键入“字符串”->OK
它可以工作,但所推断的返回类型有点难看。我们可以使用自定义实用程序类型对其进行增强,该类型可解构并重构对象类型:
type Prettify<T> = T extends infer Tb ? { [K in keyof Tb]: Tb[K] } : never;
const header = {
operationVersion: 1,
protocolVersion: 2
};
function createRequestPretty<K extends string, T>(payload: { [k in K]: T }) {
const operation = Object.keys(payload)[0] as K;
const result = Object.assign({ operation }, header, payload);
return result as any as Prettify<typeof result>;
}
const listRequest2 = createRequestPretty({ list: { a: 'aa' } });
listRequest2; // Type { operation: "list"; operationVersion: number; protocolVersion: number; list: { a: string } } -> OK
type Prettify=T扩展推断Tb?{[K-in-keyof-Tb]:Tb[K]}:从不;
常数头={
操作版本:1,
协议版本:2
};
函数createRequestPretty(有效负载:{[k in k]:T}){
常量操作=对象键(有效载荷)[0]作为K;
const result=Object.assign({operation},header,payload);
以任何形式返回结果作为美化;
}
const listRequest2=createRequestPretty({list:{a:'aa'}});
listRequest2;//键入{operation:“list”;operationVersion:编号;protocolVersion:编号;list:{a:string}}->OK
这是否可能不起作用,因为它打算使用iBasereRequest
作为类而不是接口?@sandrooco这对我来说真的不重要,只要最终结果是带有intellisense的X类型的对象:)我对类型脚本类型和泛型相当陌生
type Prettify<T> = T extends infer Tb ? { [K in keyof Tb]: Tb[K] } : never;
const header = {
operationVersion: 1,
protocolVersion: 2
};
function createRequestPretty<K extends string, T>(payload: { [k in K]: T }) {
const operation = Object.keys(payload)[0] as K;
const result = Object.assign({ operation }, header, payload);
return result as any as Prettify<typeof result>;
}
const listRequest2 = createRequestPretty({ list: { a: 'aa' } });
listRequest2; // Type { operation: "list"; operationVersion: number; protocolVersion: number; list: { a: string } } -> OK