TypeScript 检查字符串是否是接口中的键值

TypeScript check if a string is a key value in an interface

const string = 'world';
const string2 = 'bar';
const string3 = 'test';

interface example {
  hello: 'world';
  foo: 'bar';
};

如何检查字符串是否是接口中的键值?

所以在示例中 stringstring2 会通过,而 string3 会抛出错误?

谢谢!

考虑这个例子:


const string = 'world';
const string2 = 'bar';
const string3 = 'test';

interface example {
    hello: 'world';
    foo: 'bar';
};


type IsAValue<Obj, Str extends string> = {
    [Prop in keyof Obj]: Str extends Obj[Prop] ? Str : never
}[keyof Obj]

type Result1 = IsAValue<example, 'world'> // world
type Result2 = IsAValue<example, 'bar'> // bar
type Result3 = IsAValue<example, 'test'> // never

IsAValue:

Prop - 代表每个键 Obj - 代表一个对象,在我们的例子中它是 example 接口。

此实用程序类型遍历每个 Objexample)键并检查 Obj[Prop] 是否扩展了第二个参数 Strstringstring2).如果是 - 使用 Str 作为对象值,否则 - 使用 never。 utility type 末尾的这一行 [keyof Obj] 获得了对象中所有值的联合。如果一些值 mathced Str 我们将得到 Str | never。因为 never 是底部类型,并且 never 可以分配给任何类型,所以 Str | never 的并集只是 returns Str.

如果您只想从 IsAValue 获取布尔值,我的意思是 true - 值存在,false - 不存在。您可以只添加条件类型,它将检查结果是否扩展 never 或不:



const string = 'world';
const string2 = 'bar';
const string3 = 'test';

interface example {
    hello: 'world';
    foo: 'bar';
};


type IsNever<T> = [T] extends [never] ? true : false

type IsAValue<Obj, Str extends string> = IsNever<{
    [Prop in keyof Obj]: Str extends Obj[Prop] ? Str : never
}[keyof Obj]> extends false ? true : false

type Result1 = IsAValue<example, 'world'> // true
type Result2 = IsAValue<example, 'bar'> // true
type Result3 = IsAValue<example, 'test'> // false

Playground

如果你想抛出错误,请看这个例子:


const string = 'world';
const string2 = 'bar';
const string3 = 'test';

type example = {
    hello: 'world';
    foo: 'bar';
};

type Values<T> = T[keyof T]

type Assert<Obj extends Record<string, string>, Key extends Values<Obj>> = Obj

type Result1 = Assert<example, 'world'> // true
type Result2 = Assert<example, 'bar'> // true
type Result3 = Assert<example, 'test'> // false

Playground

您可能已经注意到,我已将 interface example 替换为 type example。我是故意这样做的,因为我对 Assert 类型应用了约束。第一个参数应该扩展 RecordRecord 是索引类型,而 TS 中的 interfaces 默认不索引。 您会发现更多信息 and