【问题标题】:Conditional type based on a non-empty string基于非空字符串的条件类型
【发布时间】:2021-06-23 23:09:28
【问题描述】:

有大量关于基于值的条件类型的问题。 但是我不确定是否可以实现以下场景。

我开始熟悉条件类型,我想知道是否可以创建一个依赖于非空字符串的条件类型。

让我们考虑下一个界面:

interface Animal {
    dogName: string;
    canBark: boolean;
}

interface AnimalToBeMapped {
    dogsNickname?: string;
    /// some other props
}

我正在使用这个接口来映射一个对象

function mapAnimal(animal: AnimalToBeMapped): Animal {
    return {
        dogName: animal.dogsNickname,
        canBark: !animal.dogsNickname
    }
}

仅当参数对象具有dogName 属性集时,我才将canBark 属性设置为true(也应适用于空字符串与非空字符串)。

我想要做的是为我的Animal 接口添加额外的类型安全(如果有人手动设置dogName 来定义,那么我想强制canBark 属性为true,反之亦然)。

示例:

const exmpl1: Animal = {
    dogName: 'Rex',
    canBark: false // I want an error here
}

const exmpl2: Animal = {
    dogName: '',
    canBark: true // An error here
}

【问题讨论】:

  • 您愿意接受任何解决方法吗?例如,可以创建一个接受两个参数(dogName 和 canBark)的函数吗?还是键入 wirh 泛型参数?
  • 在我看来,您正在尝试一些不是 TypeScript 设计的东西。 TypeScript 编译为 JavaScript,因此任何动态 runtime 行为都无法通过 TypeScript 键入功能强制执行。您提供的示例包含硬编码值,这些值将在编译时进行检查。但是当我读到“如果有人手动设置dogName 来定义然后我想强制canBark 属性为真,反之亦然”之类的内容时,我想到了处理用户输入或API 获取结果等场景。你在那里不走运。您需要为此编写验证逻辑。

标签: typescript


【解决方案1】:

如果它适合你,请告诉我


type NonEmptyString<T extends string> = T extends '' ? never : T;

type WithName = {
  dogName: string,
  canBark: true,
}

type WithoutName = {
  dogName?: '',
  canBark: false
};

type Animal = WithName | WithoutName;


type Overloadings =
  & ((arg: { canBark: false }) => Animal)
  & ((arg: { dogName: '', canBark: false }) => Animal)
  & (<S extends string>(arg: { dogName: NonEmptyString<S>, canBark: true }) => Animal)

const animal: Overloadings = (arg: Animal) => {
  return arg

}

const x = animal({ dogName: '', canBark: false }) // ok
const xx = animal({ dogName: 'a', canBark: true }) // ok
const xxx = animal({ dogName: 'a', canBark: false }) // error
const xxxx = animal({ dogName: '', canBark: true }) // error
const xxxxx = animal({ canBark: true }) // error
const xxxxxx = animal({ canBark: false }) // ok

Playground

TS 要区分空字符串和字符串并不是那么容易。类型 string 可分配给文字类型 ''(空字符串),这就是我使用 NonEmptyString 助手的原因

更新 如果您对不需要额外功能的更简单的解决方案感兴趣,请参阅以下示例:


type WithName = {
  dogName: string,
  canBark: true,
}

type WithoutName = {
  canBark: false
};

type Animal = WithName | WithoutName;

const x: Animal = {
  dogName: 'name',
  canBark: true
}; // ok

const xx:Animal={
  canBark:false
}; // ok

const xxx:Animal={
  canBark:true
} // expected error

const xxxx:Animal={
  dogName:''
} // expected error

Playground

【讨论】:

  • 感谢您的回答。首先,我想说的是,您的回答与往常一样是下一个级别的!惊人的!然而,在看到这个之后,我正在考虑稍微简化这种方法……你认为如果不检查属性是否为非空字符串,而是将属性 dogName 设为可选,是否可以做到?看到我们可以检查它是否存在然后锁定canBark 为真。如果dogName 不存在canBark 应该总是假的
  • @anotheruser,是的,您可以坚持使用简单的联合。我更新了我的回答
猜你喜欢
  • 1970-01-01
  • 2018-05-18
  • 1970-01-01
  • 2011-10-21
  • 2023-02-26
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 2015-06-08
相关资源
最近更新 更多