输入非假,又名“真”

问题描述 投票:0回答:3

在 TypeScript 中,有 true 类型吗?

我有这个方法:

Object.keys(lck.lockholders).length;
    enqueue(k: any, obj?: any): void

顺便说一句,我认为 TS 有一种方法可以检查空字符串

''

我想将其转换为:

    enqueue(k: Truthy, obj?: any): void

除了我不知道如何定义 Truthy 的类型。

我想要这个的原因是我不希望用户传入

null
undefined
''
等作为哈希的密钥。

typescript tsc truthy
3个回答
48
投票

我不确定你为什么需要这个,但它很有趣。老实说,简短的答案是:TypeScript 不适合这种情况,您最好进行运行时检查并记录代码,以便开发人员知道

k
参数应该是真实的。不过,如果您打算尝试强制 TypeScript 执行类似的操作,请继续阅读:


注意:要使以下代码正常工作,请打开

strictNullChecks
编译器选项。这是必要的,因为无法区分
Truthy
Truthy | null | undefined
会是一个问题。

你可以几乎定义falsy,就像

type Falsy = false | 0 | "" | null | undefined 

除了

NaN
也是假的,TypeScript 没有
NaN
的数字文字(请参阅 microsoft/TypeScript#15135)。

即使你有上面的

Falsy
,TypeScript 中也没有 否定类型(请参阅 microsoft/TypeScript#4196),因此无法将
Truthy
表示为“除了
Falsy
以外的所有类型”。

您可以尝试使用 use conditional types 来排除

enqueue()
中可能为假的参数,但这很奇怪:

type DefinitelyTruthy<T> =
  false extends T ? never :
  0 extends T ? never :
  "" extends T ? never :
  null extends T ? never :
  undefined extends T ? never :
  T

declare function enqueue<T extends number | string | true | object>(
  k: T & DefinitelyTruthy<T>,
  obj?: any
): void

declare const str: string;
enqueue(str); // error, might be falsy
enqueue("a"); // okay
enqueue(1); // okay
enqueue(0); // error
enqueue(NaN); // error
enqueue(true); // okay
enqueue(false); // error
enqueue([]); //okay
enqueue({a: "hello"}); // okay
enqueue({}); // error, interpreted as type {} which could be an empty string:
const zilch = "" as {};
enqueue(zilch); // error, see? 

注意它如何不允许任何它认为可能是假的东西,这可能就是你想要实现的目标。说不出来。


更新

我看到您编辑了问题以澄清

k
参数实际上应该是
string
(或者可能是
symbol
),并且您需要排除的唯一值是空字符串
""
。在这种情况下,您可以将上述简化为:

type DefinitelyNotEmptyString<T> = "" extends T ? never : T

declare function enqueue<T extends string | symbol>(
  k: T & DefinitelyNotEmptyString<T>,
  obj?: any
): void

enqueue(""); // error
enqueue("a"); // okay

所有这些都很棒,但不幸的是存在一个问题,如果您将通用

string
传递给
enqueue()
它将失败,有时开发人员可能需要这样做,如果他们使用
k
参数的值不是他们指定的字符串文字:

declare const str: string; // comes from somewhere else
enqueue(str); // error!  how do I do this?

为了解决这个问题,您可以尝试创建一个名义类型,您可以使用它来向编译器标识一个值已被检查为空,然后创建一个用户定义的类型保护来约束

string 
对于该类型:

type NotEmptyString = string & {"***NotEmptyString***": true};
function notEmptyString(x: string): x is NotEmptyString {
  return x !== "";
}

现在开发者可以这样做:

declare const str: string;
enqueue(str); // error, might be falsy
if (notEmptyString(str)) {
  enqueue(str); // okay, str is NotEmptyString
}

哇!这是很多跳圈。如果您认为这值得的话,这取决于您。好的,希望有帮助。祝你好运!


11
投票

没有

Truthy
类型,但是,您可以利用类型保护系统(类型谓词)来帮助 TypeScript 理解真正的
truthy
并为其分配
truthy
类型!

让我们定义

Falsy
类型和 generic
isTruthy
函数:

type Falsy = false | 0 | '' | null | undefined;

// this is a type predicate - if x is `truthy`, then it's T
const isTruthy = <T>(x: T | Falsy): x is T => !!x;

现在我们可以使用

isTruthy
函数来查找
Truthy
值,TypeScript 会正确地将
"truthy"
类型分配给结果。

示例:

{   // removing boolean "false" type
  const result: string | false = Math.random() > 0.5 ? 'a' : false;
  const truthyResult: string = isTruthy(result) ? result : 'was false';
}
{   // filtering only numbers from array
  const result: (number | undefined)[] = [42, undefined, 8, 16];
  const truthyResult: number[] = result.filter(isTruthy);
}
{   // filtering only Promises from array
  const result: (Promise<string> | null)[] = [Promise.resolve('a'), null, Promise.resolve('b'), Promise.resolve('c')];
  const truthyResult: Promise<string>[] = result.filter(isTruthy);
}


3
投票

这是一个迟到的答案,我不是 TypeScript 专家,但我正在使用

4.8.2
并且以下内容对我来说效果很好:

type Falsy = null | undefined | false | 0 | -0 | 0n | '';

type Truthy<T> = T extends Falsy ? never : T;

不幸的是我无法给出很好的解释,但下面是一个例子:

type MaybeUndefinedObject = object | undefined;

// Works
const truthyType: Truthy<MaybeUndefinedObject> = {};

// Fails with "Type 'undefined' is not assignable to type 'object'."
const truthyValue: Truthy<MaybeUndefinedObject> = undefined;

希望这对您有帮助。如果没有请举报。

© www.soinside.com 2019 - 2024. All rights reserved.