Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何对映射对象属性的TypeScript函数进行类型注释? 出身背景_Typescript - Fatal编程技术网

如何对映射对象属性的TypeScript函数进行类型注释? 出身背景

如何对映射对象属性的TypeScript函数进行类型注释? 出身背景,typescript,Typescript,假设我想从这个JSON加载一个对象: { “dateStringA”:“2019-01-02T03:04:05”, “dateStringB”:“2019-01-03T04:05:06”, “非日期字符串”:“foobar”, “someNumber”:123 } 因此,两个属性dateStringA和dateStringB实际上应该是Date类型,但由于JSON不知道类型Date,因此它是一个字符串,需要转换。因此,一个选项可能是编写一个简单的映射函数,在普通的旧JavaScript中转换如

假设我想从这个JSON加载一个对象:

{
“dateStringA”:“2019-01-02T03:04:05”,
“dateStringB”:“2019-01-03T04:05:06”,
“非日期字符串”:“foobar”,
“someNumber”:123
}
因此,两个属性
dateStringA
dateStringB
实际上应该是
Date
类型,但由于JSON不知道类型
Date
,因此它是一个
字符串,需要转换。因此,一个选项可能是编写一个简单的映射函数,在普通的旧JavaScript中转换如下属性:

函数映射属性(obj、映射器、属性){
properties.forEach(函数(属性){
obj[property]=映射器(obj[property]);
});
返回obj;
}
var usefulObject=mapProperties(
jsonObject,
函数(val){返回新日期(val);},
“dateStringA”,
“dateStringB”
);
问题 上面的工作很好,但是现在我想在TypeScript中做同样的事情,当然我想添加尽可能多的类型检查。因此,在最好的情况下,我希望得到以下结果:

//设置
常量值={dateStringA:'2019-01-02T03:04:05',dateStringB:'2019-01-03T04:05:06',非日期字符串:“”,someNumber:123};
const result=mapProperties(值,(val:string):Date=>newdate(val),'dateStringA','dateStringB');
//---测试---
//dateStringA和dateStringB现在应该是日期:
result.dateStringA.substr;//应引发编译错误-substr在类型日期不存在
result.dateStringB.substr;//应引发编译错误-substr在类型日期不存在
result.dateStringA.getDate;//应该可以
result.dateStringB.getDate;//应该可以
//非日期字符串仍然是字符串
result.nonDateString.substr;//应该可以
result.nonDateString.getDate;//应引发编译错误-类型字符串上不存在getDate
//someNumber仍然是一个数字
result.someNumber.toFixed;//应该可以
//无法对不存在的属性调用:
mapProperties(值“doesNotExist”);//应该抛出编译错误
//无法对非字符串类型的属性调用:
mapProperties(值“someNumber”);//应该抛出编译错误
到目前为止,我所尝试的: 这是我自己得到的最好的:

type PropertyNamesByType={[K in keyof O]:O[K]扩展了T?K:never}[keyof O];
类型OverwriteType=拾取和记录;
函数映射属性<
包装器类型,
WRAPPER_键扩展(WRAPPER_类型和PropertyNamesByType的键),
旧式,
新型
>(obj:WRAPPER_类型,
映射器:(值:旧类型)=>新类型,
…属性:包装器_键[]
):覆盖类型{
常量结果:OverwriteType=obj;
properties.forEach(key=>{
(结果[key])=映射器(obj[key]);
});
返回结果;
}
这似乎确实有效,但有两个奇怪之处:

  • WRAPPER\u key扩展(keyof WRAPPER\u TYPE&PropertyNamesByType)
    。我认为它应该只使用
    WRAPPER\u KEYS扩展PropertyNamesByType
    ,而不使用
    &keyof WRAPPER\u TYPE
    ,因为后者实际上不应该添加任何附加信息(我发现这完全是偶然的)。然而,如果我省略这个,TypeScript的行为就好像所有字符串属性都被转换了一样。那里发生了什么奇迹
  • (result[key])=mapper(obj[key])行中我需要这两个
    -cast。有没有办法摆脱这些

  • 可以映射属性是否显示在键列表中,然后使用转换类型或原始类型:

    // (just the type signature)
    declare function mapProperties<Json, SourceType, TargetType, P extends keyof Json>(
        obj: Json,
        converter: (value: SourceType) => TargetType,
        ...keys: P[]): { [K in keyof Json]: K extends P ? TargetType : Json[K] }
    
    //(仅限于类型签名)
    声明函数映射属性(
    obj:Json,
    转换器:(值:SourceType)=>TargetType,
    …keys:P[]:{[K in keyof Json]:K扩展了P?TargetType:Json[K]}
    
    助手类型:

    type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;
    type Morphism<T = any, U = any> = (argument: T) => U;
    

    很酷,我只需要稍微编辑一下函数就可以了。现在,我尝试创建一些如下的默认包装:
    constconvertdateproperties=(obj:T,…propertyNames:K[])=>mapProperties(obj,(val:string)=>newdate(val),propertyNames)。但这当然不起作用,因为我没有指定T[K]必须是字符串。您是否也知道此问题的解决方案?您需要通过在
    T
    上添加约束来确保值(
    T[K]
    )的类型为
    string
    。执行此操作:
    const-convertDateProperties=(obj:T,…propertyNames:K[])=>mapProperties(obj,(val:string)=>new-Date(val),…propertyNames)
    
    const transform = <T, U extends Morphism<T[K]>, K extends keyof T>(source: T, mappingFn: U, ...properties: K[]) =>
      (Object.entries(source))
        .reduce(
          (accumulator, [key, value]) => {
            const newValue =
              properties.includes(key as K)
                ? mappingFn(value)
                : value
    
            return ({ ...accumulator, [key]: newValue })
          },
          {} as Overwrite<T, Record<K, ReturnType<U>>>
        );
    
    const source = {
      dateStringA: "2019-01-02T03:04:05",
      dateStringB: "2019-01-03T04:05:06",
      nonDateString: "foobar",
      someNumber: 123
    }
    
    const toDate = (date: string) => new Date(date);
    
    console.log(
      transform(source, toDate, 'dateStringA', 'dateStringB')
    )