I have the following function:
interface BaseOptions {
prefix?: string;
}
function foo<T extends BaseOptions>(options?: T): T['prefix'] extends string ? 1 : 2 {
return 1 as any;
}
When using strictNullChecks: true I get the expected type result:
// strictNullChecks: true
const v1 = foo(); // 2
const v2 = foo({ prefix: 'bar' }) // 1
But when using strictNullChecks: false it's broken:
// strictNullChecks: false
const v12 = foo(); // 1
const v22 = foo({ prefix: 'bar' }) // 1
What's the reason for this behaviour and how can I fix it?
CodePudding user response:
Without strict null checks a type like string allows within it's definition the values null and undefined, so the type of the optional property will changed from string | undefined with strict null checks, to just string without that option (since undefined is just absorbed in to string).
This means that without strict null checks, BaseOptions['prefix'] extends string resolves to string extends string which is always true, while with strict null checks it resolves to BaseOptions['prefix'] extends string resolves to string | undefined extends string which is false.
You could use a default of never for the type parameter and test for never instead:
function foo<T extends BaseOptions = never>(options?: T): [T] extends [never] ? 2 : 1 {
return 1 as any;
}
Or if you want to check specifically for the property, you could also use keyof:
function foo<T extends BaseOptions = never>(options?: T): keyof T extends 'prefix' ? 1 : 2 {
return 1 as any;
}
