typescript 不允许呼叫任何

qpgpyjmq  于 2023-01-14  发布在  TypeScript
关注(0)|答案(1)|浏览(156)

请考虑以下函数重载:

function f(key: undefined);
function f(key: string | undefined, value: object | undefined);

我想用一个明确的未定义的f(undefined)进行合格的调用,但是对于所有其他情况需要两个参数。上面的重载工作正常,直到我传递了一个any类型的变量-看起来any可以强制转换为undefined(是的,看起来像是任何逻辑)。

如何禁止使用单个any参数的调用?

完整演示代码:

function f(key: undefined);
function f(key: string | undefined, value: object | undefined);

function f(key: string | undefined, value?: object | undefined) {
    console.log(key, value);
}

// No errors - RIGHT
f(undefined);
f("", {});
f("", undefined);
f(undefined, undefined);
f(undefined, {});

// Errors - RIGHT
f("");

// No errors - WRONG
declare var x: any;
f(x);
1hdlvixo

1hdlvixo1#

TypeScript确实不想禁止any匹配类型,因为这是any的全部意义所在。您可能需要重新考虑依赖于拒绝any的任何代码,所以要谨慎行事。
也就是说,您可以使用条件类型为any构建一个检测器,然后使用该检测器来禁止any变量。
这是探测器:

type IfAny<T, Y, N> = 0 extends (1 & T) ? Y : N;

不满足类型约束0 extends 10不能赋值给1),所以0 extends (1 & T)应该也不可能满足,因为(1 & T)应该比1还要窄,但是当Tany时,它将0 extends (1 & any)简化为0 extends any,这是满足的。这是因为any是故意不合理的,并且充当几乎所有其他类型的超类型和子类型。因此,IfAny<T, Y, N>检查T是否是any。如果是,它返回Y。如果不是,它返回N。让我们看看它是如何工作的:

type IsAny<T> = IfAny<T, true, false>
const yes: IsAny<any> = true;
const no: IsAny<string> = false;

回想一下,我说过any几乎匹配所有其他类型,唯一不匹配any的类型是never

declare const any: any;
const never: never = any; // error, any is not assignable to never

为了拒绝any参数,我们也需要这个事实。让我们将f()的第一个签名从

function f(key: undefined): void;

function f<K extends IfAny<K, never, undefined>>(key: K): void;

我们已经将key设置为泛型类型K,并将其约束为IfAny<K, never, undefined>。如果K不是any,则该约束只是undefined,因此K只能是所需的undefined。如果K * 是 * any,则该约束变为never。并且由于x1M37N1x不匹配x1M38N1x,因此它将不能满足约束。
当我们使用上面的签名时,您会看到以下行为:

f(undefined); // still works
f(""); // still error, "" is not assignable to undefined

declare var x: any;
f(x); // now error, any is not assignable to never

这正是你想要的
Playground代码链接

相关问题