我想创建一个带有两个参数的函数.一个字符串,它是确定第二个参数类型的关键,该参数类型是一个对象.字符串和对象之间的关联在单独的类型中键入.我希望在调用函数时(我已经做到了这一点)以及在函数中使用IF或Switch语句来实现完全的自动补全和类型安全!对象的类型应由字符串参数派生.

以下是一个简化的示例:


export type TLoginParameters = {
    username: string;
    otherrequiredparam: string;
    optionalparam: number;
}

export type TLogoutParameters = {
    detailsForLogginOut: string;
}



export type TStateMap = {
    login: TLoginParameters;
    logout: TLogoutParameters;
};


const edit = <K extends keyof TStateMap , T extends TStateMap[K]>(type: K, entry:T  ) => {

        switch(type) {

            case "login": {
                // i expected autocomplete for TLoginParameters- but it doesnt work :(

                const prop = entry.username;
                        
                break;
            }
        }
        
    }

// autocomplete works here

const result = edit("login", {username: "test123", otherrequiredparam: "test", optionalparam: 123 });



我try 了该函数的另一种类型定义

 <O extends TConfigTypeMap, K extends keyof O, V extends O[K]>( type: K, entry:V   ) =>

但结果是一样的.

推荐答案

TypeScrip当前无法对generic个类型参数使用control flow anlysis(当您在switch语句中选中type时得到的缩小范围).现在,当你判断type的时候,type的表观类型可以从K缩小到K & "login"左右,但K本身不受影响.据编译器所知,K可能是比"login"更宽的类型,比如完整的union type "login" | "logout".事实上,有人可能会调用edit(),第一个参数是Math.random()<0.5 ? "login" : "logout",然后你不能假设type等于"login"就意味着entry等于TLoginParameters.

GitHub中有各种悬而未决的问题,要求改善这种情况,例如microsoft/TypeScript#27808限制呼叫,以便K不能是完整的unions ,但将仅限于unions 中的一个成员.不过,就目前而言,它不是语言的一部分.如果您想使用泛型,则不能轻松使用控制流分析.如果要使用控制流分析,则不能轻松使用泛型.


不过,您的示例实际上并没有显示需要泛型.相反,看起来您希望将typeentry参数视为discriminated union类型的destructured members.例如,如果它是一个{type: "login", entry: TLoginParameters} | {type: "logout", entry: TLogoutParameters}类型的变量v,那么你可以判断v.type,它将缩小v.entry.

幸运的是,您可以通过将edit()‘S参数list视为tuple-typed rest parameters的可分辨并集来获得此效果.就像这样:

type EditParams =
  { [K in keyof TStateMap]: [type: K, entry: TStateMap[K]] }[keyof TStateMap]
/* type EditParams = 
     [type: "login", entry: TLoginParameters] | 
     [type: "logout", entry: TLogoutParameters] 
*/

const edit: (...[type, entry]: EditParams) => void = (type, entry) => {
  switch (type) {
    case "login": {
      const prop = entry.username;
      break;
    }
  }

}

这里EditParams是元组类型的区分并集,edit的输入是类型EditParams的REST参数.实现edit时,编译器将typeentry视为该元组类型联合的成员,而当您选中type时,它会自动适当地缩小entry的范围.

这就是你想要的工作方式,但不幸的是,它有点难看,或者至少让人困惑.尽管如此,这是我们目前所能做的最好的事情.

Playground link to code

Typescript相关问答推荐

无法从应用程序内的库导入组件NX Expo React Native

用泛型类型覆盖父类函数导致类型y中的Property x不能赋给基类型Parent中的相同属性."'''''' "

类型脚本强制泛型类型安全

创建一个根据布尔参数返回类型的异步函数

Angular 信号:当输入信号改变值时,S触发取数的正确方式是什么?

对扩展某种类型的属性子集进行操作的函数

参数属性类型定义的REACT-RUTER-DOM中的加载器属性错误

我可以使用TypeScrip从字符串词典/记录中填充强类型的环境对象吗?

Angular文件上传到Spring Boot失败,多部分边界拒绝

类型TTextKey不能用于索引类型 ;TOption

迭代通过具有泛型值的映射类型记录

TypeScrip:强制使用动态密钥

返回嵌套props 的可变元组

为什么特定的字符串不符合包括该字符串的枚举?

将超类型断言为类型脚本中的泛型参数

Typescript将键数组映射到属性数组

创建一个函数,该函数返回一个行为方式与传入函数相同的函数

有没有更干净的方法来更新**key of T**的值?

如何创建允许使用带有联合类型参数的Array.from()的TS函数?

在Typescript 中,是否有一种方法来定义一个类型,其中该类型是字符串子集的所有可能组合?