如何使用接口中的 属性 作为索引类型
How to use a property from an interface as an index type
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
interface In<T extends keyof Mapping> {
readonly name: T,
fn: Mapping[T]
}
const inHandlers: In<"x"> = {
name: "x",
fn(prop /* :string */) {}
}
有人知道如何获取In["name"]
的typeof作为Mapping
的索引类型吗?所以我不必写 "x"
两次
我已经试过了,不知何故 prop
变成了任何
interface In {
readonly name: keyof Mapping,
fn: Mapping[In["name"]]
}
const inHandlers: In<"x"> = {
name: "x",
fn(prop /* :any*/) {}
}
您可以使用恒等函数来约束参数类型:
function createMapping <T extends keyof Mapping>(mapping: In<T>): In<T> {
return mapping;
}
const xMapping = createMapping({
name: "x",
fn (prop) {} // prop is string
}); // xMapping is In<"x">
const yMapping = createMapping({
name: "y",
fn (prop) {} // prop is number
}); // yMapping is In<"y">
如果你预先知道 Mapping
结构,你就可以做到。
首先你需要使用mapped types创建所有possible/allowed数据结构:
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
type Variants<Dictionary> = {
[Prop in keyof Dictionary]: {
name: Prop,
fn: Dictionary[Prop]
}
}
// type Result = {
// x: {
// name: "x";
// fn: (a: string) => void;
// };
// y: {
// name: "y";
// fn: (b: number) => void;
// };
// }
type Result = Variants<Mapping>
您可能已经注意到,我们最终得到了嵌套对象,其中的值表示允许的状态。现在,我们需要以某种方式获得允许值的并集,或者换句话说,使 discriminated union type
考虑一下:
type Values<T> = T[keyof T]
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
type Variants<Dictionary> = {
[Prop in keyof Dictionary]: {
name: Prop,
fn: Dictionary[Prop]
}
}
// type Result = {
// name: "x";
// fn: (a: string) => void;
// } | {
// name: "y";
// fn: (b: number) => void;
// }
type Result = Values<Variants<Mapping>>
我已将结果包装在 Values
实用程序类型中。这种类型 returns 没有键的所有对象值的联合。这其实就是我们想要的。
我们也可以重构一下:
type Values<T> = T[keyof T]
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
type Variants<Dictionary> = Values<{
[Prop in keyof Dictionary]: {
name: Prop,
fn: Dictionary[Prop]
}
}>
type Handlers = Variants<Mapping>
const x: Handlers = {
name: "x",
fn(prop /* :string */) { }
}
const y: Handlers = {
name: "y",
fn(prop /* :number */) { }
}
您不需要使用任何额外的通用参数。
Here you can find similar question and here你可以找到我的文章
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
interface In<T extends keyof Mapping> {
readonly name: T,
fn: Mapping[T]
}
const inHandlers: In<"x"> = {
name: "x",
fn(prop /* :string */) {}
}
有人知道如何获取In["name"]
的typeof作为Mapping
的索引类型吗?所以我不必写 "x"
两次
我已经试过了,不知何故 prop
变成了任何
interface In {
readonly name: keyof Mapping,
fn: Mapping[In["name"]]
}
const inHandlers: In<"x"> = {
name: "x",
fn(prop /* :any*/) {}
}
您可以使用恒等函数来约束参数类型:
function createMapping <T extends keyof Mapping>(mapping: In<T>): In<T> {
return mapping;
}
const xMapping = createMapping({
name: "x",
fn (prop) {} // prop is string
}); // xMapping is In<"x">
const yMapping = createMapping({
name: "y",
fn (prop) {} // prop is number
}); // yMapping is In<"y">
如果你预先知道 Mapping
结构,你就可以做到。
首先你需要使用mapped types创建所有possible/allowed数据结构:
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
type Variants<Dictionary> = {
[Prop in keyof Dictionary]: {
name: Prop,
fn: Dictionary[Prop]
}
}
// type Result = {
// x: {
// name: "x";
// fn: (a: string) => void;
// };
// y: {
// name: "y";
// fn: (b: number) => void;
// };
// }
type Result = Variants<Mapping>
您可能已经注意到,我们最终得到了嵌套对象,其中的值表示允许的状态。现在,我们需要以某种方式获得允许值的并集,或者换句话说,使 discriminated union type 考虑一下:
type Values<T> = T[keyof T]
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
type Variants<Dictionary> = {
[Prop in keyof Dictionary]: {
name: Prop,
fn: Dictionary[Prop]
}
}
// type Result = {
// name: "x";
// fn: (a: string) => void;
// } | {
// name: "y";
// fn: (b: number) => void;
// }
type Result = Values<Variants<Mapping>>
我已将结果包装在 Values
实用程序类型中。这种类型 returns 没有键的所有对象值的联合。这其实就是我们想要的。
我们也可以重构一下:
type Values<T> = T[keyof T]
interface Mapping {
"x": (a: string) => void
"y": (b: number) => void
}
type Variants<Dictionary> = Values<{
[Prop in keyof Dictionary]: {
name: Prop,
fn: Dictionary[Prop]
}
}>
type Handlers = Variants<Mapping>
const x: Handlers = {
name: "x",
fn(prop /* :string */) { }
}
const y: Handlers = {
name: "y",
fn(prop /* :number */) { }
}
您不需要使用任何额外的通用参数。 Here you can find similar question and here你可以找到我的文章