如何在 Typescript 查找中匹配键和值
How to match key and value in a Typescript lookup
更新:
感谢@OliverRadini 让我到达那里。根据他们的回复,我有一个适用于我的案例的解决方案。我对他们的回答遇到的唯一问题是,我需要在外部键入您传递给函数的内容,但无法想出一种方法来推断密钥,而不是在函数中。在我的例子中,使用 util 为我们做这件事很好,如下所示:
interface ITest {
n: number;
b: boolean;
}
const f = <K extends keyof ITest>(x: { id: K; params: ITest[K] }) => ({
...x,
_propToConfirmYourUsingTheUtilNeverWriteThisManually: true,
});
type Props = ReturnType<typeof f>;
const a: Props = f({ id: "n", params: 1 }); // no type error
const b: Props = f({ id: "n", params: true }); // Type 'true' is not assignable to type 'number'
const c = f({ id: "b", params: true }); // no type error
const d = f({ id: "b", params: 1 }); // Type 'number' is not assignable to type 'boolean'
// Errors because we didn't add _propToConfirmYourUsingTheUtilNeverWriteThisManually
// This ridiculously named prop should ensure we don't override it without noticing
const z: Props = {
// Property '_propToConfirmYourUsingTheUtilNeverWriteThisManually' is missing in type ...
id: "b",
params: 7,
};
f(a); // no type error
f(b); // no type error
f(c); // no type error
f(d); // no type error
更新:
这个案子通过就好了:
const invalidProps1: Props<IdsWithParameters> = {
id: "id1",
params: {
param1: "string",
},
};
额外的属性不是这个之外的代码的问题。但是为了使这个组件函数能够通用并在 IdsWithParameters
中获取任何 id,我们不能像 @oliverradini 回复中那样明确指定密钥,如 Props<'id1'>
。但是他们的帮助使我接近了这个目标,但还没有完全实现。
interface Props<K extends keyof IdsWithParameters> {
id: K;
params: IdsWithParameters[K];
}
// Somehow want Props to know what is being used as the id and infer
// the correct params type
function Text(props: Props) {
const text = intlFunctionThatGetsTheTranslatedText(props.id, props.params);
return <>{text}</>
}
原版POST:
我正在构建一个库,我需要在其中创建一个对象(IdsWithParameters 接口),指定允许的键以及允许与每个特定键一起使用的类型化参数。在不同的地方,他们会想要指定一个对象,该对象具有 id
和 params
(Props 接口)匹配来自 IdsWithParameters 实例的 1 个特定 key/value 对。
我可以使用查找到达一个点,您必须将有效的键和参数传递给 Props 实例。但无法弄清楚如何将参数限制为与给定 key/id.
匹配的参数
interface IdsWithParameters {
id1: {};
id2: {
param1: string;
};
id3: {
param2: boolean;
param3: number;
};
}
interface Props<I extends IdsWithParameters> {
id: keyof I;
params: I[keyof I];
}
// This works as expected
const validProps1: Props<IdsWithParameters> = {
id: "id1",
params: {},
};
// This works as expected
const validProps2: Props<IdsWithParameters> = {
id: "id2",
params: {
param1: "string",
},
};
const invalidProps1: Props<IdsWithParameters> = {
id: "id1",
// Want this to error, saying that params should be {} but it passes
params: {
param1: "string",
},
};
const invalidProps2: Props<IdsWithParameters> = {
id: "id2",
// Want this to error, saying that params should be { param1: string; } but it passes
params: {},
};
我觉得我已经看这个太久了,要么有一种简单的方法,要么有更好的解决方案,但我再也看不到了。对于上下文,我正在构建一个包来处理 React 包中的可翻译内容字符串。所以它可以像这样使用:
// IdsWithParameters in above example
interface ContentStringsWithAcceptableParameters {
"errors.404.title": {},
"errors.404.content": {
pageUrl: string;
},
"errors.retryAttemptsLeft": {
attemptsLeft: number;
}
}
interface Props<I extends ContentStringsWithAcceptableParameters> {
id: keyof I;
params: I[keyof I];
}
// The react component we'll be using
function Text(props: Props<ContentStringsWithAcceptableParameters>) {
const text = intlFunctionThatGetsTheTranslatedText(props.id, props.params);
return <>{text}</>
}
如果我们稍微简化一下示例,我认为我们可以理解我们正在尝试做什么:
interface ITest {
n: number;
b: boolean;
}
const f = <K extends keyof ITest>(
x: {
id: K,
params: ITest[K],
},
) => true;
f({ id: 'n', params: 1 }); // no type error
f({ id: 'n', params: true }); // Type 'true' is not assignable to type 'number'
f({ id: 'b', params: true }); // no type error
f({ id: 'b', params: 1 }); // Type 'number' is not assignable to type 'boolean'
我们可以指定一些泛型(上例中的K
)扩展一个类型的键。然后我们可以使用该键来获取我们正在寻找的类型。
更新:
感谢@OliverRadini 让我到达那里。根据他们的回复,我有一个适用于我的案例的解决方案。我对他们的回答遇到的唯一问题是,我需要在外部键入您传递给函数的内容,但无法想出一种方法来推断密钥,而不是在函数中。在我的例子中,使用 util 为我们做这件事很好,如下所示:
interface ITest {
n: number;
b: boolean;
}
const f = <K extends keyof ITest>(x: { id: K; params: ITest[K] }) => ({
...x,
_propToConfirmYourUsingTheUtilNeverWriteThisManually: true,
});
type Props = ReturnType<typeof f>;
const a: Props = f({ id: "n", params: 1 }); // no type error
const b: Props = f({ id: "n", params: true }); // Type 'true' is not assignable to type 'number'
const c = f({ id: "b", params: true }); // no type error
const d = f({ id: "b", params: 1 }); // Type 'number' is not assignable to type 'boolean'
// Errors because we didn't add _propToConfirmYourUsingTheUtilNeverWriteThisManually
// This ridiculously named prop should ensure we don't override it without noticing
const z: Props = {
// Property '_propToConfirmYourUsingTheUtilNeverWriteThisManually' is missing in type ...
id: "b",
params: 7,
};
f(a); // no type error
f(b); // no type error
f(c); // no type error
f(d); // no type error
更新:
这个案子通过就好了:
const invalidProps1: Props<IdsWithParameters> = {
id: "id1",
params: {
param1: "string",
},
};
额外的属性不是这个之外的代码的问题。但是为了使这个组件函数能够通用并在 IdsWithParameters
中获取任何 id,我们不能像 @oliverradini 回复中那样明确指定密钥,如 Props<'id1'>
。但是他们的帮助使我接近了这个目标,但还没有完全实现。
interface Props<K extends keyof IdsWithParameters> {
id: K;
params: IdsWithParameters[K];
}
// Somehow want Props to know what is being used as the id and infer
// the correct params type
function Text(props: Props) {
const text = intlFunctionThatGetsTheTranslatedText(props.id, props.params);
return <>{text}</>
}
原版POST:
我正在构建一个库,我需要在其中创建一个对象(IdsWithParameters 接口),指定允许的键以及允许与每个特定键一起使用的类型化参数。在不同的地方,他们会想要指定一个对象,该对象具有 id
和 params
(Props 接口)匹配来自 IdsWithParameters 实例的 1 个特定 key/value 对。
我可以使用查找到达一个点,您必须将有效的键和参数传递给 Props 实例。但无法弄清楚如何将参数限制为与给定 key/id.
匹配的参数interface IdsWithParameters {
id1: {};
id2: {
param1: string;
};
id3: {
param2: boolean;
param3: number;
};
}
interface Props<I extends IdsWithParameters> {
id: keyof I;
params: I[keyof I];
}
// This works as expected
const validProps1: Props<IdsWithParameters> = {
id: "id1",
params: {},
};
// This works as expected
const validProps2: Props<IdsWithParameters> = {
id: "id2",
params: {
param1: "string",
},
};
const invalidProps1: Props<IdsWithParameters> = {
id: "id1",
// Want this to error, saying that params should be {} but it passes
params: {
param1: "string",
},
};
const invalidProps2: Props<IdsWithParameters> = {
id: "id2",
// Want this to error, saying that params should be { param1: string; } but it passes
params: {},
};
我觉得我已经看这个太久了,要么有一种简单的方法,要么有更好的解决方案,但我再也看不到了。对于上下文,我正在构建一个包来处理 React 包中的可翻译内容字符串。所以它可以像这样使用:
// IdsWithParameters in above example
interface ContentStringsWithAcceptableParameters {
"errors.404.title": {},
"errors.404.content": {
pageUrl: string;
},
"errors.retryAttemptsLeft": {
attemptsLeft: number;
}
}
interface Props<I extends ContentStringsWithAcceptableParameters> {
id: keyof I;
params: I[keyof I];
}
// The react component we'll be using
function Text(props: Props<ContentStringsWithAcceptableParameters>) {
const text = intlFunctionThatGetsTheTranslatedText(props.id, props.params);
return <>{text}</>
}
如果我们稍微简化一下示例,我认为我们可以理解我们正在尝试做什么:
interface ITest {
n: number;
b: boolean;
}
const f = <K extends keyof ITest>(
x: {
id: K,
params: ITest[K],
},
) => true;
f({ id: 'n', params: 1 }); // no type error
f({ id: 'n', params: true }); // Type 'true' is not assignable to type 'number'
f({ id: 'b', params: true }); // no type error
f({ id: 'b', params: 1 }); // Type 'number' is not assignable to type 'boolean'
我们可以指定一些泛型(上例中的K
)扩展一个类型的键。然后我们可以使用该键来获取我们正在寻找的类型。