处理要用作映射或索引属性的对象的可选属性



我正在处理一个使用indexed访问处理array类型属性的场景。尝试在这里用最简单的形式封装这个问题。

type User = {
readonly name: string; 
readonly roles: ReadonlyArray<string>;
}
const buildActions = <T extends User>(u: T) => {
// Implementation
return {login: (role: T['roles'][number]) => {
console.log(u, role);
}}
}
const actions = buildActions({name: 'user', roles: ['admin', 'client']} as const);
actions.login('client');

所以上面的代码运行良好。但在我的场景中,属性roles是可选的。

type User = {
readonly name: string; 
readonly roles?: ReadonlyArray<string>;
}

在上面的情况下,我们得到错误

类型"number"不能用于索引类型"T["roles"]">

我尝试使用条件类型来处理该场景,但没有成功。

const buildActions = <T extends User>(u: T) => {
// Implementation
return {login: (role: T['roles'] extends never ? never : T['roles'][number]) => {
console.log(u, role);
}}
}

毫无疑问,这不是处理这种场景的正确方法,但它很好地涵盖了用例。

知道如何度过这个打字场景吗?

感谢

使用条件类型解决了问题。

type User = {
readonly name: string; 
readonly roles?: ReadonlyArray<string>;
}
const buildActions = <T extends User>(u: T) => {
// Implementation
return {login: (role: T['roles'] extends string[] ? T['roles'][number] : never) => {
console.log(u, role);
}}
}
const actions = buildActions({name: 'user', roles: ['admin', 'client']} as const);
actions.login('client');

早些时候尝试过,但TSextends关键字似乎存在优先级问题。考虑到T['roles']是类型string[] | undefined以下代码工作正常:

T['roles'] extends string[] ? T['roles'][number] : never

但如果我们扭转这种状况,它就会失败。

T['roles'] extends undefined ? never : T['roles'][number] 

因此,永远不要将条件类型与undefined断言一起使用。

最新更新