【发布时间】:2020-11-17 05:38:12
【问题描述】:
在 Typescript ^3.8 中,给定这个接口...
interface IEndpoint { method: 'get'|'put'|'post'|'patch'|'delete', path: string }
还有这个常数...
const endpoint = { method: 'get', path: '/first/:firstId/second/:secondId' }
请注意,:firstId 和 :secondId 是在运行时动态提供的路径参数。我有一个函数,它将获取端点和一个带有参数值的对象,并返回 url。
function buildEndpointUrl(endpoint: IEndpoint, map: {[key: string]: string}): string;
例如:
// will set url to '/first/123/second/456'
const url = buildEndpointUrl(endpoint, {firstId: '123', secondId: '456'});
我面临的挑战是编译器将允许将垃圾作为第二个参数传递:我如何定义IEndpoint 和buildEndpointUrl,以便如果对象作为第二个参数提供,编译器会抛出错误缺少必需的密钥?
这是我尝试过的:
interface IEndpoint<T extends ReadonlyArray<string>> {
method: 'get'|'put'|'post'|'patch'|'delete',
path: string
}
const endpoint: IEndpoint<['firstId', 'secondId']> = {...};
function buildEndpointUrl<T extends ReadonlyArray<string>>(
endpoint: IEndpointConfig<T>,
map: {[key: T[number]]: string} // compiler error
);
最后一行抛出编译器错误:
TS1023:索引签名参数必须是“字符串”或“数字”
我希望 T[number] 等同于 string,因为 T extends ReadonlyArray<string> 但显然不是。我应该如何设置我的定义来增加类型安全?
【问题讨论】:
-
至少
[key: T[number]]: string应该是[key: number]: string -
我认为这行不通。它不会强制参数具有所需的属性。在上面的示例中,如果我提供
IEndpoint<['firstId', 'secondId']>作为第一个函数参数,我希望 Typescript 推断第二个参数的类型必须是{firstId: string, secondId: string} -
呼叫应该类似于
buildEndpointUrl(endpoint, ['firstId', 'secondId']);? -
否;第二个参数是一个对象,用于将路由参数的名称('firstId')映射到它的值('123')。我在帖子中举了一个例子。
-
我觉得这个问题和答案会对你有用:stackoverflow.com/questions/64744734/…
标签: typescript