如何让编译器在无效类型的定义时抱怨,而不是在使用类型时抱怨 [英] How to make compiler complain at definition on an invalid type instead complaining while type is used

查看:16
本文介绍了如何让编译器在无效类型的定义时抱怨,而不是在使用类型时抱怨的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标是定义只接受一定数量的强制参数的函数类型。

感谢@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分配给它。您拥有的唯一constraintL.List(我想,就是ReadonlyArray<any>🤷‍♂️)。但是您特别关心的是确保它最多有两个必需的参数(或类似的参数)。因此,您希望同时确保P extends L.ListN.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,因此如果继续使用f3f3of3r,则不一定会收到其他错误:

f3(1, 1, 1); // no error
如果必须这样做,您可以同时使用这两种技巧,以便输出类型也是never。但就我个人而言,我认为f3定义处的编译器错误意味着您在之后对f3所做的任何操作都是可疑的,如果它碰巧没有给出额外的错误,那也不是什么大问题。不过,还是要看你的了。

Playground link to code

这篇关于如何让编译器在无效类型的定义时抱怨,而不是在使用类型时抱怨的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆