如何让编译器在无效类型的定义时抱怨,而不是在使用类型时抱怨 [英] How to make compiler complain at definition on an invalid type instead complaining while type is used
问题描述
目标是定义只接受一定数量的强制参数的函数类型。
感谢@jcalz Whohelped me定义了类型OnlyTupleRequired
,该类型允许删除任何可选参数,并且到目前为止允许知道参数的长度,即使它们包括可选参数,我也做到了。
现在,我希望编译器对函数的定义而不是对它们的使用提出警告--任何声明‘Share Error’的注释都应该发出错误,而不会发出错误。
这里是指向playground
的链接import {L, A, N} from 'ts-toolbelt'
type OnlyTupleRequired <T extends L.List, U extends L.List = []> = {
0: T extends [infer F, ...(infer R)] ? OnlyTupleRequired <R, [...U, F]> : U
1: U
} [A.Extends <Partial <T>, T>]
type MaxParametersCount = 2
type FunctionT <P extends L.List = any, R = any> = {
1: (...params: P) => R
0: never
} [N.LowerEq <L.Length <OnlyTupleRequired <P>>, MaxParametersCount>]
declare const f0: FunctionT // should be () => any
declare const f0o: FunctionT<[1?]> // should be (a: 1?) => any
declare const f0r: FunctionT<1[]> // should be (...a: 1 []) => any
declare const f1: FunctionT<[1]> // should be (a: 1) => any
declare const f1o: FunctionT<[1, 1?]> // should be (a: 1, b?: 1) => any
declare const f1r: FunctionT<[1, ...1[]]> // should be (a: 1, ...b: 1 []) => any
declare const f2: FunctionT<[1, 1]> // should be (a: 1, b: 1) => any
declare const f2o: FunctionT<[1, 1, 1?]> // should be (a: 1, b: 1, c?: 1) => any
declare const f2r: FunctionT<[1, 1, ...1[]]> // should be (a: 1, b: 1, c?: 1) => any
declare const f3: FunctionT<[1, 1, 1]> // did not error while expecting one
declare const f3o: FunctionT<[1, 1, 1, 1?]> // did not error while expecting one
declare const f3r: FunctionT<[1, 1, 1, ...1[]]> // did not error while expecting one
f0 () // works as expected
f0o () // works as expected
f0r () // works as expected
f1 (1) // works as expected
f1o (1, 1) // works as expected
f1r (1, 1, 1) // works as expected
f2 (1, 1) // works as expected
f2o (1, 1, 1) // works as expected
f2r (1, 1, 1, 1) // works as expected
f3 (1, 1, 1) // error as expected 'never has no call sig...'
f3o (1, 1, 1) // error as expected 'never has no call sig...'
f3r (1, 1, 1) // error as expected 'never has no call sig...'
推荐答案
,因此您对FunctionT<P, R>
的定义不会阻止将P
分配给它。您拥有的唯一constraint是L.List
(我想,就是ReadonlyArray<any>
🤷♂️)。但是您特别关心的是确保它最多有两个必需的参数(或类似的参数)。因此,您希望同时确保P extends L.List
和N.LowerEq<OnlyTupleRequired<P>["length"], MaxParametersCount> extends 1
。如果后一项检查不为真,则当前您的FunctionT<P, R>
计算结果为never
。但也许我们可以重写定义,以便P
实际上受到约束:
type FunctionT<P extends (
N.LowerEq<OnlyTupleRequired<P>["length"], MaxParametersCount> extends 1
? L.List : never
) = any, R = any> = (...params: P) => R
很容易被接受;有时编译器会对循环约束不满意(其中P
直接出现在约束中),在这种情况下,有时可以(Ab)使用generic parameter defaults来规避这些问题:
type FunctionT<
P extends L.List & C = any,
R = any,
C = N.LowerEq<OnlyTupleRequired<P>["length"], MaxParametersCount> extends 1
? unknown : never
> = (...params: P) => R
但在这种情况下不需要。
让我们确保这是您想要的:
declare const f0: FunctionT; // okay
declare const f0o: FunctionT<[1?]>; // okay
declare const f0r: FunctionT<1[]>; // okay
declare const f1: FunctionT<[1]>; // okay
declare const f1o: FunctionT<[1, 1?]>; // okay
declare const f1r: FunctionT<[1, ...1[]]>; // okay
declare const f2: FunctionT<[1, 1]>; // okay
declare const f2o: FunctionT<[1, 1, 1?]>; // okay
declare const f2r: FunctionT<[1, 1, ...1[]]>; // okay
declare const f3: FunctionT<[1, 1, 1]>; // error
declare const f3o: FunctionT<[1, 1, 1, 1?]>; // error
declare const f3r: FunctionT<[1, 1, 1, ...1[]]>; // error
看起来不错。正在处理的版本继续按预期运行。这三个糟糕的版本直接在定义站点给出了编译器错误。请注意,类型本身的计算结果不再为never
,因此如果继续使用f3
、f3o
或f3r
,则不一定会收到其他错误:
f3(1, 1, 1); // no error
如果必须这样做,您可以同时使用这两种技巧,以便输出类型也是never
。但就我个人而言,我认为f3
定义处的编译器错误意味着您在之后对f3
所做的任何操作都是可疑的,如果它碰巧没有给出额外的错误,那也不是什么大问题。不过,还是要看你的了。
这篇关于如何让编译器在无效类型的定义时抱怨,而不是在使用类型时抱怨的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!