Logic with conditional
- TypeScript course
- Intermediate
- Lesson 38/89
- 4 min
Learn to build type-level logic with conditional types.
Logic with conditionals
With conditional types you can build type-level logic. The pattern T extends U ? never : T removes from T the members assignable to U; this is the basis of Exclude. Conversely T extends U ? T : never keeps only those assignable to U; this is the basis of Extract.
type Cikar<T, U> =
T extends U ? never : T;
type R = Cikar<"a" | "b", "b">;
// "a"never disappears from the union
With distributive conditionals, never disappears from a union. "a" | never | "c" = "a" | "c". This makes filtering logic work naturally: members that fail the condition become never and drop out of the result.
Practice Remove from a union
Write the conditional type Cikar<T, U> as T extends U ? never : T. Define type Kalan as Cikar<"a" | "b" | "c", "b">. Define variable dizi with type Kalan[] and assign ["a", "c"]. Print dizi[0] and dizi[1] on separate lines.
Starter code
// Cikar<T, U> koşullu türünü tanımla
// T, U'ya atanabilirsa never, değilse T
// Kalan türünü Cikar<"a" | "b" | "c", "b"> olarak tanımla
// dizi değişkenini Kalan[] türünde tanımla, ["a", "c"] ata
// dizi[0] ve dizi[1]'i ayrı satırlarda yazdırSample solution
type Cikar<T, U> = T extends U ? never : T;
type Kalan = Cikar<"a" | "b" | "c", "b">;
const dizi: Kalan[] = ["a", "c"];
console.log(dizi[0]);
console.log(dizi[1]);Expected output
a c
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What does Cikar<"a" | "b" | "c", "b"> produce?
type Cikar<T, U> = T extends U ? never : T;
type R = Cikar<"a" | "b" | "c", "b">;- "b"
- "a" | "c" Correct answer
- "a" | "b" | "c"
- never
Explanation: Distribution evaluates each member separately: "a" and "c" are not assignable to U so they stay; "b" is assignable so it becomes never and drops from the union. The result is "a" | "c".
2 Use never for filtering
type Cikar<T, U> =
T extends U ? ____ : T;
type R = Cikar<"a" | "b", "b">;
// R: "a"
type Cikar<T, U> =
T extends U ? never : T;
type R = Cikar<"a" | "b", "b">;
// R: "a"
Explanation: To remove members assignable to U you use never. any or unknown breaks the filter; T removes nothing.
3 Logic patterns
| Term | Meaning |
|---|---|
T extends U ? never : T |
Removes those assignable to U |
T extends U ? T : never |
Keeps those assignable to U |
never |
Disappears from the union |
"a" | never | "c" |
Equals "a" | "c" |