首页 > 解决方案 > 尝试创建类型检查器实用程序,但不能不出现类型错误

问题描述

我有一个我想使用的 util 函数,它将返回一个布尔值,说明一个值是否等于某种类型:

const valueIsOfType = <T>(value: T, type: string):boolean => typeof(value) === type ? true : false;

但是,当我在代码中将它用作三元运算符的条件时,如下所示:

const foo: string | JSX.Element = "bar";

return valueIsOfType(title, "string") ? truncateText(title, 18) : title;

注意:函数声明为truncateText(text, maxLength);

const truncateText = (text: string, maxLength: number):string => {
    if(text.length >= maxLength) return text.slice(0, maxLength) + "..."
    else return text;
};

我在调用行收到以下类型错误valueIsOf

“'string | JSX.Element' 类型的参数不可分配给'string' 类型的参数。'JSX.Element' 类型不可分配给'string' 类型。”

我认为这是因为 TypeScipt 无法判断我正在使用此函数检查类型,因此它会触发类型错误以防止处理不匹配的类型truncateText;

有没有一种方法可以让我使用这个工具,而不必typeof(value) === type ? true : false;为我想要检查的每种类型手动执行?为了便于阅读,我想使用这个工具或类似的东西。

标签: reactjstypescript

解决方案


我猜你想valueIsOfType()充当用户定义的类型保护函数,编译器将boolean返回值视为其参数之一是否属于某种类型的证据。如果是这样,您需要将返回类型注释为类型谓词,例如value is string.

编译器看不到typeof value === type并自动推断该函数本身是一个类型保护。有一个未解决的问题microsoft/TypeScript#16069要求提供这样的功能,但目前它不是语言的一部分。

在任何情况下,您都可以创建一个通用版本valueIsOfType()函数,它有望涵盖 JavaScripttypeof运算符的所有可能结果以及对测试对象的影响:

interface TypeofResults {
    string: string,
    number: number,
    bigint: bigint,
    boolean: boolean,
    symbol: symbol,
    undefined: undefined,
    object: object | null,
    function: Function
}

const valueIsOfType =
    <K extends keyof TypeofResults>(value: any, type: K): value is TypeofResults[K] =>
        typeof value === type

TypeofResults接口用作从结果typeof和受保护类型的映射。其中大部分都很简单,因为 TypeScript 类型名称与从typeof. 有一些是不同的......如果typeof value === "object"thenvalue是 TypeScriptobject类型,或者它是null,它不被认为可以分配给object. FunctionTypeScript 的未指定函数类型用大写字母调用F

valueIsOfType()函数是泛型的K,参数的类型,返回类型是一个类型谓词,将参数从(不需要是泛型的)type缩小到对应的属性类型从。因此,如果您调用,返回类型将是类型谓词。valueanyTypeofResultsvalueIsOfType(anyValue, "string")anyValue is string

你可以看到它有效:

function test(foo: string | number | Date) {
    if (valueIsOfType(foo, "string")) {
        console.log(foo.toUpperCase()); // foo seen to be string here
    } else if (valueIsOfType(foo, "number")) {
        console.log(foo.toFixed(2)); // foo seen to be number here
    } else {
        console.log(foo.toUTCString()) // foo seen to be Date here
    }
}

test("hello"); // HELLO
test(Math.PI); // 3.14
test(new Date()); // Sat, 12 Sep 2020 02:22:01 GMT

Playground 代码链接


推荐阅读