Infer/narrow 来自同级 属性 的函数参数
Infer/narrow function argument from sibling property
我想根据同级 属性 缩小函数参数的类型。我知道存在类型会有所帮助,但它们不可用,所以我正在使用辅助函数。感谢评论中的 jcalz,我现在有了这个
// helper function
function helper<T extends readonly unknown[]>(o: {
choices: T;
func: (opts: T[number]) => T[number];
}) {
return o;
}
helper({
choices: [
"one",
"two",
"three",
], // as const
func(o) { // should be "one" | "two" | "three", but is string
return o;
}
})
我希望 func
中的 o
是 "one" | "two" | "three"
类型,所以我的问题是打字稿不会将选择推断为元组,而是推断为 string[]
.我无法将 as const
添加到 choices
因为该函数将在 javascript.
中调用
我知道我可以将选项和函数拆分为辅助函数的单独参数,但这是不可能的,因为对象中会有更多属性。这些属性的目的是描述 func
,它需要什么作为输入以及它 returns.
最终目标是用打字稿编写辅助函数,但在 javascript 中用作类型注释。因此,在调用函数时我不能提供任何类型,也不能在标有注释的地方使用 as const
。
您希望 helper()
将数组文字 value ["one", "two", "three"]
视为具有 type ["one", "two", "three"]
;也就是说,像 ["one", "two", "three"] as const
这样的 tuple of string literal types instead of as just string[]
. This is easy enough to do from the caller's side of the function; callers can use a const
assertion。但是在调用者不想(或不能)使用 const
断言的情况下,让函数本身来执行它会很好。
我刚才打开 microsoft/TypeScript#30680 寻求一些简单的方法来做到这一点。也许它看起来像:
// INVALID TYPESCRIPT SYNTAX, DO NOT TRY THIS
// vvvvv
function helper<T extends const readonly unknown[]>(o: {
choices: T;
func: (opts: T[number]) => T[number];
}) {
return o;
}
其中 const
可以以某种方式应用于泛型类型参数。不幸的是,这不是当前语言的一部分。
幸运的是,有一些技巧可以让编译器的行为有点类似。
如果您想给编译器提示它应该推断文字类型,您可以查看 microsoft/TypeScript#10676. If a type parameter is constrained to a type that includes string
, then the compiler will tend to infer string literal types. The same goes for number
. So while an unconstrained T
(like T extends unknown
) will infer string
when it sees "one"
, a constrained T extends string
will infer "one"
. If you don't really want to constrain the type parameter, then you need to come up with the widest possible constraint that contains string
and/or number
explicitly. You can't use the unknown
type,因为 T extends string | unknown
会立即折叠为 T extends unknown
。但是你可以做类似
的事情
type Narrowable = string | number | bigint | boolean |
symbol | object | undefined | void | null | {};
然后写T extends Narrowable
而不是T extends unknown
。或者在您的情况下,T extends readonly Narrowable[]
而不是 T extends readonly unknown[]
.
如果您希望编译器推断元组而不是数组类型,还有其他技巧。引入了 TypeScript 4.0 variadic tuple types。如果 U
是类数组类型参数,那么编译器将倾向于看到 (arr: U)
并为 U
推断无序数组类型。但是如果你写 (arr: [...U])
或 `(arr: readonly [...U]),它会倾向于推断一个元组类型。
结合这些得到:
function helper<T extends readonly Narrowable[]>(o: {
choices: readonly [...T];
func: (opts: T[number]) => T[number];
}) {
return o;
}
您可以验证它是否有效:
helper({
choices: [
"one",
"two",
"three",
], // as const
func(o) { // "one" | "two" | "three"
return o;
}
})
看起来不错。
我想根据同级 属性 缩小函数参数的类型。我知道存在类型会有所帮助,但它们不可用,所以我正在使用辅助函数。感谢评论中的 jcalz,我现在有了这个
// helper function
function helper<T extends readonly unknown[]>(o: {
choices: T;
func: (opts: T[number]) => T[number];
}) {
return o;
}
helper({
choices: [
"one",
"two",
"three",
], // as const
func(o) { // should be "one" | "two" | "three", but is string
return o;
}
})
我希望 func
中的 o
是 "one" | "two" | "three"
类型,所以我的问题是打字稿不会将选择推断为元组,而是推断为 string[]
.我无法将 as const
添加到 choices
因为该函数将在 javascript.
我知道我可以将选项和函数拆分为辅助函数的单独参数,但这是不可能的,因为对象中会有更多属性。这些属性的目的是描述 func
,它需要什么作为输入以及它 returns.
最终目标是用打字稿编写辅助函数,但在 javascript 中用作类型注释。因此,在调用函数时我不能提供任何类型,也不能在标有注释的地方使用 as const
。
您希望 helper()
将数组文字 value ["one", "two", "three"]
视为具有 type ["one", "two", "three"]
;也就是说,像 ["one", "two", "three"] as const
这样的 tuple of string literal types instead of as just string[]
. This is easy enough to do from the caller's side of the function; callers can use a const
assertion。但是在调用者不想(或不能)使用 const
断言的情况下,让函数本身来执行它会很好。
我刚才打开 microsoft/TypeScript#30680 寻求一些简单的方法来做到这一点。也许它看起来像:
// INVALID TYPESCRIPT SYNTAX, DO NOT TRY THIS
// vvvvv
function helper<T extends const readonly unknown[]>(o: {
choices: T;
func: (opts: T[number]) => T[number];
}) {
return o;
}
其中 const
可以以某种方式应用于泛型类型参数。不幸的是,这不是当前语言的一部分。
幸运的是,有一些技巧可以让编译器的行为有点类似。
如果您想给编译器提示它应该推断文字类型,您可以查看 microsoft/TypeScript#10676. If a type parameter is constrained to a type that includes string
, then the compiler will tend to infer string literal types. The same goes for number
. So while an unconstrained T
(like T extends unknown
) will infer string
when it sees "one"
, a constrained T extends string
will infer "one"
. If you don't really want to constrain the type parameter, then you need to come up with the widest possible constraint that contains string
and/or number
explicitly. You can't use the unknown
type,因为 T extends string | unknown
会立即折叠为 T extends unknown
。但是你可以做类似
type Narrowable = string | number | bigint | boolean |
symbol | object | undefined | void | null | {};
然后写T extends Narrowable
而不是T extends unknown
。或者在您的情况下,T extends readonly Narrowable[]
而不是 T extends readonly unknown[]
.
如果您希望编译器推断元组而不是数组类型,还有其他技巧。引入了 TypeScript 4.0 variadic tuple types。如果 U
是类数组类型参数,那么编译器将倾向于看到 (arr: U)
并为 U
推断无序数组类型。但是如果你写 (arr: [...U])
或 `(arr: readonly [...U]),它会倾向于推断一个元组类型。
结合这些得到:
function helper<T extends readonly Narrowable[]>(o: {
choices: readonly [...T];
func: (opts: T[number]) => T[number];
}) {
return o;
}
您可以验证它是否有效:
helper({
choices: [
"one",
"two",
"three",
], // as const
func(o) { // "one" | "two" | "three"
return o;
}
})
看起来不错。