【问题标题】:How do I dynamically index a record with known types in TypeScript?如何在 TypeScript 中动态索引具有已知类型的记录?
【发布时间】:2020-09-21 08:12:36
【问题描述】:

我正在尝试使用可能也可以键入的字符串动态索引具有已知类型的记录,下面是所有相关代码,包括在我的 reduce (acc[val]) 中显示的错误,我遇到了麻烦了解错误,所以我不知道如何解决它

interface CommandsPingDescription {
  type: string;
  props: never;
}
interface LocalizationMap {
  "commands.ping.description": CommandsPingDescription;
}
import base from "../locale/base.json";
import en from "../locale/en.json";

type Language = keyof typeof languages;

const languages: Record<"en", typeof base> = { en };

export const setLanguage = <T extends Language>(lang: T) => {
  return <
    K extends keyof LocalizationMap,
    V extends LocalizationMap[K]["props"]
  >(
    key: K,
    ...placeholders: V[]
  ) => {
    let translation = key
      .split(".")
      .reduce((acc, val) => acc[val], languages[lang]);
(parameter) acc: Record<"en", {
    commands: {
        ping: {
            description: string;
        };
    };
}>[T]
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ commands: { ping: { description: string; }; }; }'.
  No index signature with a parameter of type 'string' was found on type '{ commands: { ping: { description: string; }; }; }'.

游乐场链接:https://www.typescriptlang.org/play/#code/MYewdgzgLgBARgQwgUxgXhgbwFAzzUAW0ITABMIAuLXfOgBwEswBzanOz-M5CYAJ0b0ojcNQBE42lwC+0mHLnZQkWMjDoadIiXJUtXGE1bt5hmDz6DhosBPEBuM-jl1F2bFACe9VABlSFgBXBBZUDABrZC8QADMYb184mAAbQJCwiCdlcGhU9NDeagAlZFB+MgAecXVxABoEn2RkxBQAPk1MGHUFbOQAD3oQflgVPJQoANYM8JhKgBVu-qh1Chgp4MK2gAo0kxh5gEp0Do58fmQoIP4NSuc8AGkllb0YKJj4vxBgBBTGAC8ECJwABZBD0Or3GAANWeqwg62+vwBQNsYPoAG0HgBdDHiej8ED0CDibHyHZQ97UB6Q8wAOgZ9DSwGQAAsQCkePx9NCMWS6Mc0KcoSlLgl+KQIGlgRpItEoXQ6RAmYwoNtxHTxIcFfg6RcyEEWdttghgMAGgA3X6Cjqm4AYq0pbENPabTIY13Yw5ONzYJTMFb8WKm1AAYRAxFIFAACswWAARXgCIQygyJZDUaCCVg+oyE4nUMDIC3IfhOOQB0vBlmIn5-QEy9EGcQ6KMQOnGFh0yzJmzgcTUcORvSx1iJqwp2zloA

【问题讨论】:

  • 考虑修改此代码以构成一个minimal reproducible example,该minimal reproducible example 可以放入像The Playground 这样的独立IDE 中,以展示您所看到的内容。例如,也许您可​​以提供baseen 类型,或者通过简化代码来消除对它们的依赖。祝你好运!
  • base 是 json,其结构类似于错误中显示的内容,记录只接受 typeof base 的 json,这意味着 en 与 base 相同
  • 我启用了 resolveJsonModules
  • 如果我不能快速将它放到一个独立的 IDE 中并进行复制,那么我获得它的机会就会更小。也许其他人愿意在不复制的情况下回答或尝试更加努力地复制它,但是如果您提供易于理解的minimal reproducible example,您获得好答案的机会将会增加。祝你好运!
  • 我添加了游乐场的链接

标签: typescript typescript-typings


【解决方案1】:

您的代码的核心似乎在这里:

const key = "commands.ping.description";
const en = {
    commands: {
        ping: {
            description: "";
        }
    }
}
let translation = key
    .split(".")
    .reduce((acc, val) => acc[val], en);

而你想让 TypeScript 做的就是找出acc[val] 的类型在哪里 valkey 的子字符串。那不会发生;它远远超出了字符串文字类型的限制,而且有充分的理由。

我建议你做的是将你的类型放宽为这样的:

const key = "commands.ping.description";
interface RecursiveRecord<T> {
    [key: string]: T | RecursiveRecord<T>;
}
const en: RecursiveRecord<string> = {
    commands: {
        ping: {
            description: "hello";
        }
    }
}

// go through the properties from key.split(".") 
// and assign the string at the end to translation
let record = en;
let translation: string = "";
for (const substr of key.split(".")) {
    const oneLevelDeeper = record[substr];
    if (typeof oneLevelDeeper === "string") {
        translation = oneLevelDeeper
        break;
    } else {
        record = oneLevelDeeper;
    }
}
console.log(translation); // "hello"

【讨论】:

    猜你喜欢
    • 2021-01-18
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    相关资源
    最近更新 更多