-
Notifications
You must be signed in to change notification settings - Fork 13k
Description
TypeScript Version: 3.9.6 (npm and in vs code)
Search Terms:
declaration intellisense
Code
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
Expected behavior:
I'm trying to extract a type mapping from an object containing native type validation function so for example, if I have the object
const test = {
Test: {
Test1: {
Test2: SimpleStringValidator //return type is string or undefined but input can be anything
},
}
}
I want to generate the type.
type Extracted = {
Test: {
Test1: {
Test2: string
}
}
}
and have it be the same in intellisense and in the generated type declaration file. In the above example this generated type should be the return value type of the
Actual behavior:
Intellisense and the output declaration file are inconsistent. Intellisense creates a nested type with type string at property Test2 (this is the desired behaviour) but the output declaration file is as follows
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;
};
};
In the declaration file the Test1 definition gets blown away to any, which leads me to not be able to directly import the generated type into other projects.
Playground Link:
The issue is reproducible in the typescript playground. Intellisense displays the Test2 property correctly as type string, where in the d.ts file Test1 is of type any. Tried with typescript versions 3.9.2 and 4.0.0-beta
Playground Link
ts compiler options:
"compilerOptions": {
"noImplicitAny": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"alwaysStrict": true,
"esModuleInterop": true,
"declaration": true,
"emitDecoratorMetadata": true,
"moduleResolution": 2,
"target": "ES2019",
"module": "ESNext"
}
Related Issues: