首页 > 解决方案 > 如何将接口泛型限制为仅字符串或对象或 null?

问题描述

export interface Foo<T extends string | object | null> {
  bar: T;
}

type Callback<T = any> = (res: T) => void

function hydra<T extends string | object | null>(callback: Callback<Foo<T>>) {
    callback({
        bar: 'Hello World'
    });
}

我不工作。它抛出这个错误:

Type '"Hello World"' is not assignable to type 'T'.
  '"Hello World"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string | object | null'.

游乐场链接

我该如何解决这个问题?

标签: typescript

解决方案


这里的主要问题是,尽管文字Hello World可以分配给 a string,但具有通用参数(作为约束)的事实依赖于可能不满足的子string类型。Hello World

假设这种情况

type StringSubtype = 'Not Hello World';
hydra<StringSubtype>(res => {
    // ...
});

函数的通用参数hydra现在是string. 而且,确实,它满足extends string | object | null约束。都有效。
但是,res.bar是类型'Not Hello World',这意味着没有其他字符串值可以匹配该类型。

hydra<StringSubtype>(res => {
    // ...

    // Type '"Hello World"' is not assignable to type '"Not Hello World"'
    res = {
        bar: `Hello World`
    };
});

这就是您的编译错误所说的

类型“Hello World”不能分配给类型“T”。'"Hello World"' 可分配给'T' 类型的约束,但'T' 可以用约束'string | 的不同子类型实例化。对象 | 无效的'。

即使Hello World可分配给string,编译器也不保证它T可以是 的子类型string

解决方案

只需不要将您的hydra函数声明为通用函数。直接使用更灵活的联合类型作为类型参数Foo<>

function hydra(callback: Callback<Foo<string | object | null>>) {
    callback({
        bar: 'Hello World'
    });
}

编辑:替代解决方案

  1. 强制转换Hello WorldT
function hydra<T extends string | object | null>(callback: Callback<Foo<T>>) {
    callback({
        bar: 'Hello World' as unknown as T
    });
}
  1. T与强制值联合
function hydra<T extends string | object | null>(callback: Callback<Foo<T | 'Hello World'>>) {
    callback({
        bar: 'Hello World'
    });
}

但是,足够深入,如果您将值强制为res.bar,则没有理由有任何通用参数。
但是,您的示例是一个示例,我想这应该是有原因的……我希望这三种解决方法中的任何一种都符合您的意图。

我至少解释了错误是什么。所以你可以用这些知识来实现​​你所需要的,我猜。

希望能帮助到你。


推荐阅读