TypeScript 增强字面量类型的成员,如const数组类型(例如,字符串字面量类型应该具有字面长度属性)

ws51t4hk  于 2个月前  发布在  TypeScript
关注(0)|答案(9)|浏览(43)

const数组类型,其主要成员也是常量。当定义一个const数组[number, string, boolean]时,它的length类型是3。此外,当访问特殊索引时,类型也会指向确切的const类型。

function const_array(): void
{
    let elements: [number, string, false] = [3, "something", false];
    let length: 3 = elements.length;

    let first: number = elements[0];
    let second: string = elements[1];
    let third: false = elements[2];
}

然而,字面量类型与const数组类型不同。当定义一个字面量类型"something"时,它的length不是9而是number。此外,当访问特殊索引时,类型不是特殊的字面量类型,而是string类型。

function literal(): void
{
    let word: "something" = "something" as const;
    let length: number = something.length; // not 9 but number

    let first: string = word[0]; // not "s" but string
    let second: string = word[1]; // not "o" but string
    let third: string = word[2]; // not "m" but string
}

那么,如何将字面量类型增强为类似于const数组类型的呢?

ui7jx7zq

ui7jx7zq1#

听起来像是#34589的重复。

bqf10yzr

bqf10yzr2#

不,我不这么认为。#34589 是关于元组类型的。这是关于使用字面量类型为 .length 和字符串字面量的元素。

cygmwpex

cygmwpex3#

了解为什么这会有用会很好。

unftdfkk

unftdfkk4#

要实现对 边缘下划线字符串 的类型检测,我已经发布了一个新的 issue

type is_edge_underscored<P> = P extends string
    ? P[0] extends "_"
        ? true
        : P[typeof (P.length - 1)] extends "_"
            ? true
            : false
    : false;

,希望 (Literal.length - 1) 也是常量值。然而,我不能确定我已经为 边缘下划线字符串 请求了确切的功能。如果我遗漏了什么重要的事情,请告知我。

jtw3ybtb

jtw3ybtb5#

有很多使用场景
一个使用场景是Assert一个方法只被调用一次,模仿其他语言中的 char 类型:

type SingleChar = string & { length: 1 };
const charCodeOf = (char: SingleChar): number => char.charCodeAt(0);

charCodeOf('a'); // Should work
charCodeOf('asdhfkj') // Should fail
charCodeOf('') // Should also fail

还防止将字面空字符串作为参数传递:

type EmptyString = string & { length: 0 };
type SingleChar = string & { length: 1 };

const lastChar = (str: Exclude<string, EmptyString>): SingleChar => str[str.length - 1]!;

lastChar('abc'); // Should work
lastChar(''); // Should fail

// We could also better narrow the return types

const typedLastChar = <S extends string>(
  str: S,
): S extends EmptyString ? undefined : SingleChar => str[str.length - 1];

const ch1: string = typedLastChar('qwe'); // should work
const ch2: string = typedLastChar(''); // should fail
const ch3: undefined = typedLastChar(''); // should work

我相信还有其他固定长度字符串的用例(固定长度哈希?或者身份证?)
在我看来,这个建议是一个非常好的补充,对于DSLs和构建器来说非常棒。

oxiaedzo

oxiaedzo6#

另一个用例:目前,某些类型级别的算术利用数组长度产生数字字面量的事实。这会导致性能问题。在 type-plus 中,我正在进行这项工作,并在开发过程中需要将位数限制为3-4位,以便IDE仍然具有性能优势。

如果 'abc'['length'] 获得与 [1,1,1]['length'] 相同的处理方式,那么可能会有显著的性能提升。

类型级别算术的另一个例子是:Implementing Arithmetic Within TypeScript’s Type System

当然,最佳解决方案是添加

type Add<A extends number, B extends number> = intrinsic
type Subtract<A extends number, B extends number> = intrinsic
type Increment<A extends number> = Add<A, 1>
type Decrement<A extends number> = Subtract<A, 1>

🍺

qxsslcnc

qxsslcnc7#

正如指出的,我认为在字符串上有一些更好的打字可能性会很好。

使用案例

// --- Improved getter
type FirstChar = 'foobar'[0] // 'f'
type LastChar = 'foobar'[-1] // 'r'

// --- Intrinsic type to get character at index
type FirstChar = CharAt<'foobar', 0>> // 'f'
type LastChar = CharAt<'foobar', -1> // 'r'

// --- Character ranges
type ARange = 'a0' ... 'a1' // 'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5' | 'a6' | 'a7' | 'a8' | 'a9'
type HexCharacter = 'a' ... 'f' | '0' ... '9' // 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

// --- Intrinsic types to restrict string character and size
type HexString = StringOf<HexCharacter>
type RGB = StringOf<HexCharacter, 6, 8>
type MD5 = StringOf<HexCharacter, 32>
type LenghtOf3 = StringOf<3>
type LenghtOf3To6 = StringOf<3, 6>

// --- Use cases
const hex: HexString = 'abcdef0123465789'
const rgb: RGB = 'ff0080'
const rgba: RGB = 'ff0080ff'
const MD5: RGB = '3858f62230ac3c915f300c664312c63f'
wnvonmuf

wnvonmuf8#

你好,对于那些正在寻找更高效解决方案的人,我已经为那些仍然面临这个问题但由于其性能不佳而无法使用线性实现的人创建了一个对数实现。
编辑:嗯,我会考虑一个对数字符串索引器。

icnyk63a

icnyk63a9#

关于这个PR是否受欢迎?如果受欢迎,我想尝试一下。

相关问题