Let's take a specific example:
interface Sample {
x?: number;
y: string;
}
The objective is to create a new type as follows:
interface NewSample {
x: number;
}
The goal is to eliminate all fields that can contain null
or undefined
, and make the remaining fields non-nullable.
This is the expected behavior:
const newS1: NewSample = {}; // should NOT be valid
const newS2: NewSample = {x: 1}; // should be valid
const newS3: NewSample = {y: ''}; // should NOT be valid
const newS4: NewSample = {z: 0}; // should NOT be valid
const newS5: NewSample = {x: 1, y: ''}; // should NOT be valid
Here is an attempt that needs fixing (comments explain what it does versus what it should do):
export type FilterNullable<T> = {
[K in keyof T]: T[K] extends undefined | null ? NonNullable<T[K]> : never;
};
const s1: FilterNullable<Sample> = {}; // should NOT be valid, error: missing property 'y'
const s2: FilterNullable<Sample> = {x: 1}; // should be valid, but gives incorrect error - "should be number not undefined"
const s3: FilterNullable<Sample> = {y: ''}; // should NOT be valid, incorrectly showing "string not never"
const s4: FilterNullable<Sample> = {z: 0}; // should NOT be valid, correct error - "property z does not exist"
const s5: FilterNullable<Sample> = {x: 1, y: ''}; // should NOT be valid, wrong errors shown - "number not undefined, string not never"
The issue may lie in the conditional types, but further clarification from documentation is needed for potential solutions.