typescript 有没有办法在编译时提取类型的键?

t30tvxxf  于 2023-03-13  发布在  TypeScript
关注(0)|答案(1)|浏览(121)

我在想,是否可以这样做:

type FooBar = {
    foo: number,
    bar: number
}

const obj = {
    foo: 3,
    bar: 2
}

const keys = KeysOf<FooBar>() // keys = ["foo", "bar"]
function isFooBar(obj: any): boolean {
    for(key of keys) {
        if (!(key in obj)) {
            return false 
        }
    }
}

我知道TypeScript中的类型是一个开发概念,但是通过使TypeScript编译器提取这些键也可以实现这一点。

fcg9iug3

fcg9iug31#

你不能这样做,因为TypeScript类型信息在运行时是不可用的。你必须有一个运行时数组["foo", "bar"],以实现你的类型 predicate 。但这似乎意味着名称在两个地方,这是一个维护问题。
当我在这种情况下,我通常会把它的头打开,创建运行时数组,然后根据数组定义类型和类型 predicate ,如下所示:

const fooBarKeys = ["foo", "bar"] as const;

type TypeHelper<Keys extends PropertyKey> = {
    [Key in Keys]: number;
};

type FooBar = TypeHelper<typeof fooBarKeys[number]>;
//   ^? type FooBar = { foo: number; bar: number; }

function isFooBar(obj: any): obj is FooBar {
    for (const key of fooBarKeys) {
        if (typeof obj[key] !== "number") {
            return false;
        }
    }
    return true;
}

类型 predicate 的使用示例:

console.log(isFooBar({foo: 42, bar: 67}));  // true
console.log(isFooBar({foo: 42}));           // false

Playground链接
你也可以通过使用“模型对象”来实现,这只是从运行时可用的数据结构构建类型信息的同一概念的不同方法:

const fooBarModel = {
    foo: 42,
    bar: 67,
};

type FooBar = typeof fooBarModel;
//   ^? type FooBar = { foo: number; bar: number; }

const fooBarKeys = Object.keys(fooBarModel) as Array<keyof FooBar>;

function isFooBar(obj: any): obj is FooBar {
    for (const key of fooBarKeys) {
        if (typeof obj[key] !== typeof fooBarModel[key]) { // This is imperfect, but better than nothing
            return false;
        }
    }
    return true;
}

console.log(isFooBar({foo: 42, bar: 67}));  // true
console.log(isFooBar({foo: 42}));           // false

Playground链接

相关问题