在 TypeScript 中,要获取一个联合类型所代表的具体类型,我们通常使用类型守卫(Type Guards)或类型断言(Type Assertions)。以下是几种常用的方法:

  1. 使用 typeof 类型守卫:

对于基本类型,我们可以使用 typeof 操作符:

type StringOrNumber = string | number;
 
function processValue(value: StringOrNumber) {
    if (typeof value === 'string') {
        console.log('It\'s a string:', value.toUpperCase());
    } else {
        console.log('It\'s a number:', value.toFixed(2));
    }
}
  1. 使用 instanceof 类型守卫:

对于类的实例,我们可以使用 instanceof 操作符:

class Dog {
    bark() { console.log('Woof!'); }
}
 
class Cat {
    meow() { console.log('Meow!'); }
}
 
type Animal = Dog | Cat;
 
function makeSound(animal: Animal) {
    if (animal instanceof Dog) {
        animal.bark();
    } else {
        animal.meow();
    }
}
  1. 使用自定义类型守卫:

对于更复杂的类型,我们可以定义自己的类型守卫函数:

interface Square {
    kind: 'square';
    size: number;
}
 
interface Rectangle {
    kind: 'rectangle';
    width: number;
    height: number;
}
 
type Shape = Square | Rectangle;
 
function isSquare(shape: Shape): shape is Square {
    return shape.kind === 'square';
}
 
function calculateArea(shape: Shape) {
    if (isSquare(shape)) {
        return shape.size * shape.size;
    } else {
        return shape.width * shape.height;
    }
}
  1. 使用 in 操作符:

对于对象类型,我们可以使用 in 操作符检查属性是否存在:

type Bird = { fly: () => void };
type Fish = { swim: () => void };
 
function move(animal: Bird | Fish) {
    if ('fly' in animal) {
        animal.fly();
    } else {
        animal.swim();
    }
}
  1. 使用类型断言:

在某些情况下,你可能确定知道类型,可以使用类型断言:

type Result = string | number;
 
function processResult(result: Result) {
    const stringResult = result as string;
    console.log(stringResult.toUpperCase());
    // 注意:这种方法不安全,如果类型猜测错误,可能导致运行时错误
}
  1. 使用 switch 语句和可辨识联合:

对于具有共同属性的联合类型,可以使用 switch 语句:

interface Circle {
    kind: 'circle';
    radius: number;
}
 
interface Square {
    kind: 'square';
    sideLength: number;
}
 
type Shape = Circle | Square;
 
function getArea(shape: Shape) {
    switch(shape.kind) {
        case 'circle':
            return Math.PI * shape.radius ** 2;
        case 'square':
            return shape.sideLength ** 2;
    }
}
  1. 使用条件类型(Conditional Types):

在泛型或高级类型操作中,可以使用条件类型:

type ExtractStringType<T> = T extends string ? T : never;
 
type NumberOrString = number | string;
type JustString = ExtractStringType<NumberOrString>; // 结果是 string

这些方法让你可以在运行时或类型系统中确定联合类型的具体类型。选择哪种方法取决于你的具体需求和类型的结构。类型守卫通常是最安全和最常用的方法,因为它们提供了运行时的类型检查。