gpt4 book ai didi

javascript - 带后缀的键类型

转载 作者:行者123 更新时间:2023-12-04 07:37:49 26 4
gpt4 key购买 nike

是否可以使用 typescript 定义 state 的键?应该是 lowercase + some string ?

type HasSufix = `${Lowercase<string>}Required`

interface SomeShape {
[key: HasSufix]: boolean
}

const state: SomeShape = {
usersRequired: false,
ordersRequired: false,
booksRequired: false,
};

最佳答案

当前 TypeScript 中没有与您想要的 SomeShape 相对应的特定类型类型。 Lowercase<string>评估为只是 string ;即使这不是真的,pattern template literal types喜欢 `${string}Required`当前不能用作对象的键类型;见 microsoft/TypeScript#42192想要查询更多的信息。
相反,您可以代表 SomeShape作为 generic用作候选类型约束的类型。也就是说,你创建了一个类似 ValidSomeShape<T> 的类型。 ,使得 T extends ValidSomeShape<T>当且仅当 T是有效的 SomeShape .它可能看起来像这样:

type ValidSomeShape<T extends object> = { [K in keyof T as
K extends `${infer P}Required` ? `${Lowercase<P>}Required` :
`${Lowercase<Extract<K, string>>}Required`]:
boolean
} extends infer O ? {[K in keyof O]: O[K]} : never;
其工作方式是:编译器 re-maps the keysT对那些有效的;如果 key K不以 "Required" 结尾,然后我们附加它。否则,我们在 "Required" 之前转动零件变成自己的小写版本。我们确保属性类型是 boolean .
末尾带有 extends infer O ? ... 的部分是 trick from the answer to another question这鼓励编译器列出 ValidSomeShape<T> 的实际属性在 IntelliSense 中,而不是显示相当不透明的 ValidSomeShape<T>姓名。你宁愿看到 {fooRequired: boolean}在错误消息中而不是 ValidSomeShape<{foo: string}> .

继续:阻止人们手动指定 T ,你可以制作一个通用的辅助函数 asSomeShape()推断 T从它的输入:
const asSomeShape = <T extends ValidSomeShape<T>>(obj: T) => obj;
所以,而不是注释 const state: SomeShape = {...} , 你写 const state = asSomeShape({...}) .

让我们试试看:
const state = asSomeShape({
usersRequired: false,
ordersRequired: false,
booksRequired: false,
}); // okay
这编译没有错误。但是当你做错事时,注意会发生什么:
const badState1 = asSomeShape({
usersRequired: false,
ordersRequired: 123, // error!
//~~~~~~~~~~~~~~ <-- // Type 'number' is not assignable to type 'boolean'
booksRequired: false,
}); // okay

const badState2 = asSomeShape({
usersRequired: false,
ordersRequired: false,
BooksRequired: false, // error!
//~~~~~~~~~~~~~~~~~~~~
// Object literal may only specify known properties, but 'BooksRequired' does not exist in type
// '{ usersRequired: boolean; ordersRequired: boolean; booksRequired: boolean; }'.
// Did you mean to write 'booksRequired'?
}); // okay

const badState3 = asSomeShape({
users: false, // error!
//~~~~~~~~~~~~
// Object literal may only specify known properties, and 'users' does not exist in type
// '{ usersRequired: boolean; ordersRequired: boolean; booksRequired: boolean; }'
ordersRequired: false,
booksRequired: false,
}); // okay
您可以看到每个失败都会产生有用的错误消息。 ordersRequired属性是 number而不是预期的 boolean ; BooksRequired属性应该是 booksRequired ;和 users属性也是错误的(编译器似乎不认为它足够接近 usersRequired 来暗示你应该写它,但它确实说它希望在那里看到 usersRequired)。

因此,至少从 TypeScript 4.2 开始,这已经足够了。
由于通用约束比特定类型使用起来更复杂,您可能只想使用 ValidSomeShape<T>在与尚未验证的对象交互的函数中......就像某些库的面向外部的端点。验证对象后,您可以将其类型扩展为不太精确但非通用的类型,例如 Record<string, boolean>或其他东西,并将其作为更广泛的类型在您的库中传递:
export function userFacingLibraryFunction<T extends ValidSomeShape<T>>(someShape: T): void {
// now that someShape has been validated, we can pass it to our internal functions:
internalLibraryFunction(someShape);
}

// not exported
function internalLibraryFunction(alreadyValidatedSomeShape: Record<string, boolean>): void {
Object.keys(alreadyValidatedSomeShape).filter(k => alreadyValidatedSomeShape[k]);
}

Playground link to code

关于javascript - 带后缀的键类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67646907/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com