簡體   English   中英

Typescript 中的遞歸類型映射

[英]Recursive Type Mapping in Typescript

我正在嘗試從包含本機類型驗證 function 的 object 中提取類型映射,例如,如果我有 object

const test  = {
  Test: {
    Test1: {
      Test2: SimpleStringValidator //return type is string or undefined but input can be anything
    },
  }
}

我想提取類型

type Extracted = {
  Test: {
    Test1: {
      Test2: string
    }
  }
}

為此,我編寫了以下代碼來提取包含一組嵌套驗證函數的 object 的返回類型

樣本.ts


export type Validator<T> = NativeTypeValidator<T> | ObjectValidator<T>

export type NativeTypeValidator<T> = (n: any) => T | undefined
export type ObjectValidator<O> = {
  [K in keyof O]: Validator<O[K]> 
}

//native validators
export const SimpleStringValidator:NativeTypeValidator<string> = (val) => typeof(val) === "string" ? val : undefined

//object validator function
export const ObjValidator = <V>(validatorObj: ObjectValidator<V>) => (o:any):V =>{
  let result = {} as V;
  //we can only validate objects
  if (typeof (o) !== "object") { return undefined; }
  const validatorKeys = Object.keys(o) as [keyof ObjectValidator<V>]
  validatorKeys.forEach((validatorKey) => { 
    const objValue = o[validatorKey] as V[keyof V];
    const objectValidator = validatorObj[validatorKey]
    if (!objectValidator) { return undefined } //do nothing if no validator exists for the key in o
    //figure out if we have a nested object validator or a native validator at the corresponding key of validatorObj
    if (typeof (objectValidator) === "object") {
      result[validatorKey] = ObjValidator(objectValidator as ObjectValidator<V[keyof V]>)(objValue)
    }
    else {
      const nativeValidator = objectValidator as NativeTypeValidator<V[keyof V]>;
      result[validatorKey] = nativeValidator(objValue)
    }
  })
  return result;
}

export const test  = {
  Test: {
    Test1: {
      Test2: SimpleStringValidator
    },
  }
}

export const validatorFunc = ObjValidator(test);
export const outputExample = validatorFunc({
  Test: {
    Test1: {
      Test2: "hi"
    },
  }
})

outputExample.Test.Test1.Test2 = "1";
outputExample.Test.Test1.Test2 = 1; //vs code intellisense complains because needs to be type string

在我的情況下,智能感知自動完成嵌套屬性 Test2 並將類型作為字符串,但是當我創建類型聲明文件時,類型信息不同,我無法將此生成的類型正確導出到其他項目。 具體來說,它將屬性 Test1 的類型設置為 any。 我要生成的類型是驗證器函數的 output 和上面代碼中的 outputExample 類型。

生成的sample.d.ts

export declare type Validator<T> = NativeTypeValidator<T> | ObjectValidator<T>;
export declare type NativeTypeValidator<T> = (n: any) => T | undefined;
export declare type ObjectValidator<O> = {
    [K in keyof O]: Validator<O[K]>;
};
export declare const SimpleStringValidator: NativeTypeValidator<string>;
export declare const ObjValidator: <V>(validatorObj: ObjectValidator<V>) => (o: any) => V;
export declare const test: {
    Test: {
        Test1: {
            Test2: NativeTypeValidator<string>;
        };
    };
};
export declare const validatorFunc: (o: any) => {
    Test: {
        Test1: any;
    };
};
export declare const outputExample: {
    Test: {
        Test1: any;
    };
};

我需要使用根驗證器 object 作為提取類型的源,以尋找生成的聲明文件具有正確類型的解決方案。 我在 Typescript 操場上有這段代碼,它顯示了自動完成和放入 .d.ts 文件的內容之間的區別。

打字稿游樂場示例

如果要提取:

{
  Test: {
    Test1: {
      Test2: string
    }
  }
}

您可以使用這種遞歸類型映射,使用infer

type ValidatedObject<T> = Partial<{
  [key in keyof T]: T[key] extends ObjectValidator<infer Type>
    ? ValidatedObject<Type>
    : T[key] extends NativeTypeValidator<infer Type>
    ? Type
    : T[key] extends object
    ? ValidatedObject<T[key]>
    : T[key];
}>

操場

注意:partial 的存在有兩個原因,一個是類型完全輸出到.d.ts文件中,另一個是undefined的返回值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM