键入对象中的键,其中该键的值满足约束
Type for keys in object, where value of that key satisfies constraint
我有这样的东西:
显然这是一个过于简单的例子,所以我为什么要专门做这些类型的问题是无关紧要的。
type Bird = { kind: "bird" }
type Fish = { kind: "fish" }
const zoo = {
flamingo: { kind: "bird" },
hawk: { kind: "bird" },
chicken: { kind: "bird" },
guppy: { kind: "fish" },
blowfish: { kind: "fish" }
}
我想获取可能是这样的字符串数组类型:
type FishInZoo = "guppy" | "blowfish"
type BirdInZoo = "flamingo" | "hawk" | "chicken"
所以我在想类似下面的内容,但我不知道语法是什么:
type FishInZoo = keyof typeof zoo where { kind: "fish" }
这可能吗?
我相信您正在寻找类似的东西:
type GetKeysOfType<
Type extends Record<string, any>,
Obj extends Record<string, any>
> = keyof {
[Key in keyof Obj as Obj[Key] extends Type ? Key : never]: Obj[Key];
}
请注意,这将需要对对象 see docs 进行 as const
断言。这允许您在对象和类型中使用字符串文字,即
type Bird = { kind: "bird" }
type Fish = { kind: "fish" }
// as opposed to
type Kind = { kind: string };
使用它需要您指定:
const zoo = {
flamingo: { kind: "bird" },
hawk: { kind: "bird" },
chicken: { kind: "bird" },
guppy: { kind: "fish" },
blowfish: { kind: "fish" }
} as const // this as const.
然后你使用这样的类型:
type BirdsInZoo = GetKeysOfType<Bird, typeof zoo>
type FishesInZoo = GetKeysOfType<Fish, typeof zoo>
您还可以强制所有使用 GetKeysOfType
的对象必须是 Readonly
,即必须使用 as const
以防止人们忘记和接收不正确的值。但这取决于您的用例。
它使用了4.1中发布的相对较新的key remapping feature。
除了上面@zecuria 的出色回答之外,还有一些额外的注意事项,与我对这种类型的实际使用有关。
type GetKeysOfType<
Type extends Record<string, any>,
Obj extends Record<string, any>
> = keyof {
[Key in keyof Obj as Obj[Key] extends Type ? Key : never]: Obj[Key];
};
const initialFilters = {
sportId: { key: "sportId", kind: "type", types: [] as String[] },
gameType: { key: "gameType", kind: "type", types: [] as String[] },
contestTypeId: { key: "contestTypeId", kind: "type", types: [] as String[] },
entryFees: {
kind: "range",
key: "entryFees",
max: 10000,
min: 0,
},
} as const;
type TypeFilterKey = GetKeysOfType<TypeFilter, typeof initialFilters>;
重要的是 initialFilters
中对象值的 as String[]
。
没有它,types
将是 readonly []
类型,而不是可变的 String[]
类型,类似于
filter.types.includes(type)
将失败
TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
我有这样的东西:
显然这是一个过于简单的例子,所以我为什么要专门做这些类型的问题是无关紧要的。
type Bird = { kind: "bird" }
type Fish = { kind: "fish" }
const zoo = {
flamingo: { kind: "bird" },
hawk: { kind: "bird" },
chicken: { kind: "bird" },
guppy: { kind: "fish" },
blowfish: { kind: "fish" }
}
我想获取可能是这样的字符串数组类型:
type FishInZoo = "guppy" | "blowfish"
type BirdInZoo = "flamingo" | "hawk" | "chicken"
所以我在想类似下面的内容,但我不知道语法是什么:
type FishInZoo = keyof typeof zoo where { kind: "fish" }
这可能吗?
我相信您正在寻找类似的东西:
type GetKeysOfType<
Type extends Record<string, any>,
Obj extends Record<string, any>
> = keyof {
[Key in keyof Obj as Obj[Key] extends Type ? Key : never]: Obj[Key];
}
请注意,这将需要对对象 see docs 进行 as const
断言。这允许您在对象和类型中使用字符串文字,即
type Bird = { kind: "bird" }
type Fish = { kind: "fish" }
// as opposed to
type Kind = { kind: string };
使用它需要您指定:
const zoo = {
flamingo: { kind: "bird" },
hawk: { kind: "bird" },
chicken: { kind: "bird" },
guppy: { kind: "fish" },
blowfish: { kind: "fish" }
} as const // this as const.
然后你使用这样的类型:
type BirdsInZoo = GetKeysOfType<Bird, typeof zoo>
type FishesInZoo = GetKeysOfType<Fish, typeof zoo>
您还可以强制所有使用 GetKeysOfType
的对象必须是 Readonly
,即必须使用 as const
以防止人们忘记和接收不正确的值。但这取决于您的用例。
它使用了4.1中发布的相对较新的key remapping feature。
除了上面@zecuria 的出色回答之外,还有一些额外的注意事项,与我对这种类型的实际使用有关。
type GetKeysOfType<
Type extends Record<string, any>,
Obj extends Record<string, any>
> = keyof {
[Key in keyof Obj as Obj[Key] extends Type ? Key : never]: Obj[Key];
};
const initialFilters = {
sportId: { key: "sportId", kind: "type", types: [] as String[] },
gameType: { key: "gameType", kind: "type", types: [] as String[] },
contestTypeId: { key: "contestTypeId", kind: "type", types: [] as String[] },
entryFees: {
kind: "range",
key: "entryFees",
max: 10000,
min: 0,
},
} as const;
type TypeFilterKey = GetKeysOfType<TypeFilter, typeof initialFilters>;
重要的是 initialFilters
中对象值的 as String[]
。
没有它,types
将是 readonly []
类型,而不是可变的 String[]
类型,类似于
filter.types.includes(type)
将失败
TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.