Typescript: 提案正芏衚珟で怜蚌された文字列型

䜜成日 2016幎01月22日  Â·  146コメント  Â·  ゜ヌス: microsoft/TypeScript

プロパティが単なる文字列たたは文字列のセットではなく、パタヌンに䞀臎する必芁がある堎合がありたす。

let fontStyle: 'normal' | 'italic' = 'normal'; // already available in master
let fontColor: /^#([0-9a-f]{3}|[0-9a-f]{6})$/i = '#000'; // my suggestion

JavaScriptでは、DOMノヌドやさたざたなサヌドパヌティラむブラリのcssスタむルの反映など、css衚蚘で色の倀を栌玍するのが䞀般的です。

どう思いたすか

Literal Types Needs Proposal Suggestion

最も参考になるコメント

蚭蚈提案

そこ開発者はその埌、単なる文字列より指定された倀を必芁ずするずき䟋がたくさんありたすが、単玔な文字列リテラル䟋えばCSSの色、電子メヌル、電話番号、郵䟿番号、の和集合ずしおそれらを列挙するこずはできたせん闊歩拡匵子さえなどJSONスキヌマ仕様は、どの䞀般JSONオブゞェクトのスキヌマを蚘述するために䜿甚されるのは、TSタむプシステムの芳点からregex-validated string typeおよびregex-validated string type of indexず呌ばれる可胜性のあるpatternおよびpatternPropertiesを持っおいたす。

目暙

開発者に、JSONスキヌマに䞀歩近い型システムを提䟛したす。これは、開発者が䞀般的に䜿甚し、必芁に応じお文字列怜蚌チェックを忘れないようにしたす。

構文の抂芁

この機胜の実装は、次の4぀の郚分で構成されおいたす。

正芏衚珟で怜蚌されたタむプ

type CssColor = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
type Email = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i;
type Gmail = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;

正芏衚珟で怜蚌された倉数タむプ

let fontColor: /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;

同じですが、より読みやすく

let fontColor: CssColor;

正芏衚珟で怜蚌された倉数タむプのむンデックス

interface UsersCollection {
    [email: /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i]: User;
}

同じですが、より読みやすく

interface UsersCollection {
    [email: Email]: User;
}

可倉型の型ガヌド

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(color)) {
        fontColor = color;// correct
    }
}

ず同じ

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (!(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(color))) return;
    fontColor = color;// correct
}

読みやすさを向䞊させるために定矩された型を䜿甚する

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (CssColor.test(color)) {
        fontColor = color;// correct
    }
}

ず同じ

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (!(CssColor.test(color))) return;
    fontColor = color;// correct
}

むンデックスタむプのタむプgurard

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i.test(email)) {
        collection[email];// type is User
    }
}

ず同じ

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (!(/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i.test(email))) return;
    collection[email];// type is User
}

読みやすさを向䞊させるために定矩された型を䜿甚する

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (Email.test(email)) {
        collection[email];// type is User
    }
}

ず同じ

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (!(Email.test(email))) return;
    collection[email];// type is User
}

セマンティックの抂芁

割り圓お

let email: Email;
let gmail: Gmail;
email = '[email protected]';// correct
email = '[email protected]';// correct
gmail = '[email protected]';// compile time error
gmail = '[email protected]';// correct
gmail = email;// obviously compile time error
email = gmail;// unfortunately compile time error too

残念ながら、この蚘事によるパフォヌマンスぞの倧きな圱響なしに、ある正芏衚珟が別の正芏衚珟のサブタむプであるかどうかを確認するこずはできたせん。 したがっお、制限する必芁がありたす。 ただし、次の回避策がありたす。

// explicit cast
gmail = <Gmail>email;// correct
// type guard
if (Gmail.test(email)) {
    gmail = email;// correct
}
// another regex subtype declaration
type Gmail = Email & /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;
gmail = email;// correct

残念ながら、 string倉数のregex-validated string倉数ぞの割り圓おも制限する必芁がありたす。これは、コンパむル時に正芏衚珟ず䞀臎するずいう保蚌がないためです。

let someEmail = '[email protected]';
let someGmail = '[email protected]';
email = someEmail;// compile time error
gmail = someGmail;// compile time error

ただし、ここに瀺すように、明瀺的なキャストガヌドたたは型ガヌドを䜿甚でき
幞いなこずに、文字列リテラルの堎合はそうではありたせん。文字列リテラルを䜿甚しおいるずきに、その倀が正芏衚珟ず䞀臎するこずを確認できるからです。

let someEmail: '[email protected]' = '[email protected]';
let someGmail: '[email protected]' = '[email protected]';
email = someEmail;// correct
gmail = someGmail;// correct

むンデックスの型絞り

むンデックスのregex-validated typeの単玔なケヌスに぀いおは、むンデックスタむプのタむプgurardを参照しおください。
しかし、もっず耇雑なケヌスがあるかもしれたせん

type Email = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i;
type Gmail = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;
interface UsersCollection {
    [email: Email]: User;
    [gmail: Gmail]: GmailUser;
}
let collection: UsersCollection;
let someEmail = '[email protected]';
let someGmail = '[email protected]';
collection['[email protected]'];// type is User
collection['[email protected]'];// type is User & GmailUser
collection[someEmail];// unfortunately type is any
collection[someGmail];// unfortunately type is any
// explicit cast is still an unsafe workaround
collection[<Email> someEmail];// type is User
collection[<Gmail> someGmail];// type is GmailUser
collection[<Email & Gmail> someGmail];// type is User & GmailUser

リテラルにはそのような問題はありたせん。

let collection: UsersCollection;
let someEmail: '[email protected]' = '[email protected]';
let someGmail: '[email protected]' = '[email protected]';
collection[someEmail];// type is User
collection[someGmail];// type is User & GmailUser

ただし、倉数の堎合、次のより珟実的な䟋のように、タむプガヌドを䜿甚するのが最善のオプションです。

getUserByEmail(email: string) {
    collection[email];// type is any
    if (Email.test(email)) {
        collection[email];// type is User
        if (Gmail.test(email)) {
            collection[email];// type is User & GmailUser
        }
    }
    if (Gmail.test(email)) {
        collection[email];// type is GmailUser
    }
}

しかし、 Gmail型に察しおより適切な定矩を䜿甚するず、別の型の絞り蟌みが行われたす。

type Gmail = Email & /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (Email.test(email)) {
        collection[email];// type is User
        if (Gmail.test(email)) {
            collection[email];// type is User & GmailUser
        }
    }
    if (Gmail.test(email)) {
        collection[email];// type is User & GmailUser
    }
}

和集合ず亀差点

実際には、䞀般的なタむプずregex-validatedタむプは実際には異なるため、correcltyがそれらの和集合ず共通郚分を凊理する方法のルヌルが必芁です。

type Regex_1 = / ... /;
type Regex_2 = / ... /;
type NonRegex = { ... };
type test_1 = Regex_1 | Regex_2;// correct
type test_2 = Regex_1 & Regex_2;// correct
type test_3 = Regex_1 | NonRegex;// correct
type test_4 = Regex_1 & NonRegex;// compile time error
if (test_1.test(something)) {
    something;// type is test_1
    // something matches Regex_1 OR Regex_2
}
if (test_2.test(something)) {
    something;// type is test_2
    // something matches Regex_1 AND Regex_2
}
if (test_3.test(something)) {
    something;// type is Regex_1
} else {
    something;// type is NonRegex
}

ゞェネリック

ゞェネリックには特別なケヌスはないので、 regex-validated型は、通垞の型ず同じようにゞェネリックで䜿甚できたす。
以䞋のような制玄のあるゞェネリックスの堎合、 regex-validated型は文字列のように動䜜したす。

class Something<T extends String> { ... }
let something = new Something<Email>();// correct

攟出の抂芁

通垞のタむプずは異なり、 regex-validatedは攟出にいくらかの圱響を及がしたす。

type Regex_1 = / ... /;
type Regex_2 = / ... /;
type NonRegex = { ... };
type test_1 = Regex_1 | Regex_2;
type test_2 = Regex_1 & Regex_2;
type test_3 = Regex_1 | NonRegex;
type test_4 = Regex_1 & NonRegex;
if (test_1.test(something)) {
    /* ... */
}
if (test_2.test(something)) {
    /* ... */
}
if (test_3.test(something)) {
    /* ... */
} else {
    /* ... */
}

コンパむルされたす

var Regex_1 = / ... /;
var Regex_2 = / ... /;
if (Regex_1.test(something) || Regex_2.test(something)) {
    /* ... */
}
if (Regex_1.test(something) && Regex_2.test(something)) {
    /* ... */
}
if (Regex_1.test(something)) {
    /* ... */
} else {
    /* ... */
}

互換性の抂芁

この機胜は、それを壊す可胜性があるケヌスのみがあり、 regex-validatedタむプが通垞のタむプずは異なり圱響を䞎えるこずに関連しおいるため、互換性に問題はありたせん。したがっお、これは有効なTSコヌドです。

type someType = { ... };
var someType = { ... };

以䞋のコヌドがそうでない堎合

type someRegex = / ... /;
var someRegex = { ... };

しかし、2番目はすでに無効でしたが、別の理由型宣蚀が間違っおいたが原因です。
したがっお、この型がregex-validated堎合に備えお、型ず同じ名前の倉数の宣蚀を制限する必芁がありたす。

PS

私がおそらく芋逃したこずを自由に指摘しおください。 この提案が気に入ったら、それをカバヌするテストを䜜成しお、PRずしお远加しおみおください。

党おのコメント146件

ええ、私はこれがDefinitelyTypedを介しおコヌミングするのを芋たした。 サヌビスレむダヌで

䞻な問題は次のずおりです。

  • これらをうたく構成する方法は明確ではありたせん。 "cat" 、 "dog" 、および"fish"コンマ区切りリストが必芁な堎合は、 /dog|cat|fish(,(dog|cat|fish))*/ように蚘述する必芁がありたす。

    • "cat" 、 "dog "、および"fish"文字列リテラル型を蚘述する型がすでにある堎合、それらをこの正芏衚珟に統合するにはどうすればよいですか

    • 明らかにここには繰り返しがありたすが、これは望たしくありたせん。 おそらく、前の問題を修正するず、これが簡単になりたす。

  • 非暙準の拡匵機胜は、この皮の問題を匕き起こしたす。

これに関する巚倧な+ 1、ZipCode、SSN、ONet、これに関する他の倚くのナヌスケヌス。

同じ問題に盎面したしたが、ただ実装されおいないこずがわかりたした。おそらく、この回避策が圹立぀でしょう。
http://stackoverflow.com/questions/37144672/guid-uuid-type-in​​-typescript

@mhegazyが提案したように、私はここに私の提案8665を眮きたす。 型宣蚀で単玔な怜蚌関数を蚱可するのはどうですか そんな感じ

type Integer(n:number) => String(n).macth(/^[0-9]+$/)
let x:Integer = 3 //OK
let y:Integer = 3.6 //wrong

type ColorLevel(n:number) => n>0 && n<= 255
type RGB = {red:ColorLevel, green:ColorLevel, blue:ColorLevel};
let redColor:RGB = {red:255, green:0, blue:0}   //OK
let wrongColor:RGB = {red:255, green:900, blue:0} //wrong

type Hex(n:string) => n.match(/^([0-9]|[A-F])+$/)
let hexValue:Hex = "F6A5" //OK
let wrongHexValue:Hex = "F6AZ5" //wrong

タむプが受け入れるこずができる倀は、関数パラメヌタヌタむプず関数評䟡自䜓によっお決定されたす。 それは7982も解決したす。

@rylphs +1これにより、TypeScriptは非垞に匷力になりたす

サブタむピングは_regex-validatedstring types_でどのように機胜したすか

let a: RegExType_1
let b: RegExType_2

a = b // Is this allowed? Is RegExType_2 subtype of RegExType_1?
b = a // Is this allowed? Is RegExType_1 subtype of RegExType_2?

ここで、 RegExType_1ずRegExType_2は_正芏衚珟で怜蚌された文字列型_です。

線集この問題は倚項匏時間で解決できるようです正芏衚珟の包含問題を参照。

TypeStyleにも圹立ちたす https 

JSXでは、 @ RyanCavanaughず私は、人々がaria- および堎合によっおはdata- 属性を远加するのを芋おきたした。 誰かが実際にキャッチオヌルずしおDefinitelyTypedに文字列むンデックス眲名を远加したした。 このための新しいむンデックス眲名が圹立぀でしょう。

interface IntrinsicElements {
    // ....
    [attributeName: /aria-\w+/]: number | string | boolean;
}

蚭蚈提案

そこ開発者はその埌、単なる文字列より指定された倀を必芁ずするずき䟋がたくさんありたすが、単玔な文字列リテラル䟋えばCSSの色、電子メヌル、電話番号、郵䟿番号、の和集合ずしおそれらを列挙するこずはできたせん闊歩拡匵子さえなどJSONスキヌマ仕様は、どの䞀般JSONオブゞェクトのスキヌマを蚘述するために䜿甚されるのは、TSタむプシステムの芳点からregex-validated string typeおよびregex-validated string type of indexず呌ばれる可胜性のあるpatternおよびpatternPropertiesを持っおいたす。

目暙

開発者に、JSONスキヌマに䞀歩近い型システムを提䟛したす。これは、開発者が䞀般的に䜿甚し、必芁に応じお文字列怜蚌チェックを忘れないようにしたす。

構文の抂芁

この機胜の実装は、次の4぀の郚分で構成されおいたす。

正芏衚珟で怜蚌されたタむプ

type CssColor = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
type Email = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i;
type Gmail = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;

正芏衚珟で怜蚌された倉数タむプ

let fontColor: /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;

同じですが、より読みやすく

let fontColor: CssColor;

正芏衚珟で怜蚌された倉数タむプのむンデックス

interface UsersCollection {
    [email: /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i]: User;
}

同じですが、より読みやすく

interface UsersCollection {
    [email: Email]: User;
}

可倉型の型ガヌド

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(color)) {
        fontColor = color;// correct
    }
}

ず同じ

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (!(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(color))) return;
    fontColor = color;// correct
}

読みやすさを向䞊させるために定矩された型を䜿甚する

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (CssColor.test(color)) {
        fontColor = color;// correct
    }
}

ず同じ

setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (!(CssColor.test(color))) return;
    fontColor = color;// correct
}

むンデックスタむプのタむプgurard

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i.test(email)) {
        collection[email];// type is User
    }
}

ず同じ

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (!(/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i.test(email))) return;
    collection[email];// type is User
}

読みやすさを向䞊させるために定矩された型を䜿甚する

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (Email.test(email)) {
        collection[email];// type is User
    }
}

ず同じ

let collection: UsersCollection;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (!(Email.test(email))) return;
    collection[email];// type is User
}

セマンティックの抂芁

割り圓お

let email: Email;
let gmail: Gmail;
email = '[email protected]';// correct
email = '[email protected]';// correct
gmail = '[email protected]';// compile time error
gmail = '[email protected]';// correct
gmail = email;// obviously compile time error
email = gmail;// unfortunately compile time error too

残念ながら、この蚘事によるパフォヌマンスぞの倧きな圱響なしに、ある正芏衚珟が別の正芏衚珟のサブタむプであるかどうかを確認するこずはできたせん。 したがっお、制限する必芁がありたす。 ただし、次の回避策がありたす。

// explicit cast
gmail = <Gmail>email;// correct
// type guard
if (Gmail.test(email)) {
    gmail = email;// correct
}
// another regex subtype declaration
type Gmail = Email & /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;
gmail = email;// correct

残念ながら、 string倉数のregex-validated string倉数ぞの割り圓おも制限する必芁がありたす。これは、コンパむル時に正芏衚珟ず䞀臎するずいう保蚌がないためです。

let someEmail = '[email protected]';
let someGmail = '[email protected]';
email = someEmail;// compile time error
gmail = someGmail;// compile time error

ただし、ここに瀺すように、明瀺的なキャストガヌドたたは型ガヌドを䜿甚でき
幞いなこずに、文字列リテラルの堎合はそうではありたせん。文字列リテラルを䜿甚しおいるずきに、その倀が正芏衚珟ず䞀臎するこずを確認できるからです。

let someEmail: '[email protected]' = '[email protected]';
let someGmail: '[email protected]' = '[email protected]';
email = someEmail;// correct
gmail = someGmail;// correct

むンデックスの型絞り

むンデックスのregex-validated typeの単玔なケヌスに぀いおは、むンデックスタむプのタむプgurardを参照しおください。
しかし、もっず耇雑なケヌスがあるかもしれたせん

type Email = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i;
type Gmail = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;
interface UsersCollection {
    [email: Email]: User;
    [gmail: Gmail]: GmailUser;
}
let collection: UsersCollection;
let someEmail = '[email protected]';
let someGmail = '[email protected]';
collection['[email protected]'];// type is User
collection['[email protected]'];// type is User & GmailUser
collection[someEmail];// unfortunately type is any
collection[someGmail];// unfortunately type is any
// explicit cast is still an unsafe workaround
collection[<Email> someEmail];// type is User
collection[<Gmail> someGmail];// type is GmailUser
collection[<Email & Gmail> someGmail];// type is User & GmailUser

リテラルにはそのような問題はありたせん。

let collection: UsersCollection;
let someEmail: '[email protected]' = '[email protected]';
let someGmail: '[email protected]' = '[email protected]';
collection[someEmail];// type is User
collection[someGmail];// type is User & GmailUser

ただし、倉数の堎合、次のより珟実的な䟋のように、タむプガヌドを䜿甚するのが最善のオプションです。

getUserByEmail(email: string) {
    collection[email];// type is any
    if (Email.test(email)) {
        collection[email];// type is User
        if (Gmail.test(email)) {
            collection[email];// type is User & GmailUser
        }
    }
    if (Gmail.test(email)) {
        collection[email];// type is GmailUser
    }
}

しかし、 Gmail型に察しおより適切な定矩を䜿甚するず、別の型の絞り蟌みが行われたす。

type Gmail = Email & /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@gmail\.com$/i;
getUserByEmail(email: string) {
    collection[email];// type is any
    if (Email.test(email)) {
        collection[email];// type is User
        if (Gmail.test(email)) {
            collection[email];// type is User & GmailUser
        }
    }
    if (Gmail.test(email)) {
        collection[email];// type is User & GmailUser
    }
}

和集合ず亀差点

実際には、䞀般的なタむプずregex-validatedタむプは実際には異なるため、correcltyがそれらの和集合ず共通郚分を凊理する方法のルヌルが必芁です。

type Regex_1 = / ... /;
type Regex_2 = / ... /;
type NonRegex = { ... };
type test_1 = Regex_1 | Regex_2;// correct
type test_2 = Regex_1 & Regex_2;// correct
type test_3 = Regex_1 | NonRegex;// correct
type test_4 = Regex_1 & NonRegex;// compile time error
if (test_1.test(something)) {
    something;// type is test_1
    // something matches Regex_1 OR Regex_2
}
if (test_2.test(something)) {
    something;// type is test_2
    // something matches Regex_1 AND Regex_2
}
if (test_3.test(something)) {
    something;// type is Regex_1
} else {
    something;// type is NonRegex
}

ゞェネリック

ゞェネリックには特別なケヌスはないので、 regex-validated型は、通垞の型ず同じようにゞェネリックで䜿甚できたす。
以䞋のような制玄のあるゞェネリックスの堎合、 regex-validated型は文字列のように動䜜したす。

class Something<T extends String> { ... }
let something = new Something<Email>();// correct

攟出の抂芁

通垞のタむプずは異なり、 regex-validatedは攟出にいくらかの圱響を及がしたす。

type Regex_1 = / ... /;
type Regex_2 = / ... /;
type NonRegex = { ... };
type test_1 = Regex_1 | Regex_2;
type test_2 = Regex_1 & Regex_2;
type test_3 = Regex_1 | NonRegex;
type test_4 = Regex_1 & NonRegex;
if (test_1.test(something)) {
    /* ... */
}
if (test_2.test(something)) {
    /* ... */
}
if (test_3.test(something)) {
    /* ... */
} else {
    /* ... */
}

コンパむルされたす

var Regex_1 = / ... /;
var Regex_2 = / ... /;
if (Regex_1.test(something) || Regex_2.test(something)) {
    /* ... */
}
if (Regex_1.test(something) && Regex_2.test(something)) {
    /* ... */
}
if (Regex_1.test(something)) {
    /* ... */
} else {
    /* ... */
}

互換性の抂芁

この機胜は、それを壊す可胜性があるケヌスのみがあり、 regex-validatedタむプが通垞のタむプずは異なり圱響を䞎えるこずに関連しおいるため、互換性に問題はありたせん。したがっお、これは有効なTSコヌドです。

type someType = { ... };
var someType = { ... };

以䞋のコヌドがそうでない堎合

type someRegex = / ... /;
var someRegex = { ... };

しかし、2番目はすでに無効でしたが、別の理由型宣蚀が間違っおいたが原因です。
したがっお、この型がregex-validated堎合に備えお、型ず同じ名前の倉数の宣蚀を制限する必芁がありたす。

PS

私がおそらく芋逃したこずを自由に指摘しおください。 この提案が気に入ったら、それをカバヌするテストを䜜成しお、PRずしお远加しおみおください。

regex-validatedタむプの共通郚分ず和集合のいく぀かのケヌスを指摘するのを忘れたしたが、最新のテストケヌスでそれらを説明したした。 その小さな倉曎を反映するためにDesign proposalを曎新する必芁がありたすか

@Igmat 、あなたのデザむン提案に぀いおの質問攟出の抂芁に぀いお詳しく

@alexanderbird 、はい、他のタむプは攟出に圱響を䞎えたせん。 最初は、 regex-validatedでもそうなるず思っおいたので、提案を䜜成し、提案された構文で遊んでみたした。
最初のアプロヌチは次のようなものでした。

let fontColor: /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
fontColor = "#000";

この

type CssColor: /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
let fontColor: CssColor;
fontColor = "#000";

"#000"はコンパむル時にチェックできるため、問題はなく、倉曎を発行する必芁もありたせん。
ただし、䟿利にするために、 stringからregex-validatedタむプぞの絞り蟌みも凊理する必芁がありたす。 だから私は以前の䞡方のセットアップでこれに぀いお考えたした

let someString: string;
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(someString)) {
    fontColor = someString; // Ok
}
fontColor = someString; // compile time error

したがっお、正芏衚珟はあたり読みにくく、すべおの堎所にコピヌする必芁があるため、ナヌザヌが簡単に間違える可胜性があるこずを陀けば、emitには圱響せず、問題ないように芋えたす。 しかし、この特定のケヌスでは、 type動䜜を倉曎するよりも優れおいるようです。
しかし、それから私はこのようなものに気づきたした

let someString: string;
let email: /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/I;
if (/^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i.test(someString)) {
    email = someString; // Ok
}
email = someString; // compile time error

悪倢です。 そしお、それは亀差点や和集合がなくおもです。 したがっお、このような事態が発生しないようにするには、提案に瀺されおいるように、 type攟出をわずかに倉曎する必芁がありたす。

@DanielRosenwasser 、この提案に察するフィヌドバックをお願いしたす。 たた、可胜であれば、ここで参照されおいるテストに぀いおもどうでしょうか。
この機胜の実装を本圓に手䌝いたいのですが、時間がかかりたす tscは非垞に耇雑なプロゞェクトであり、内郚でどのように機胜するかを理解するために䜜業する必芁がありたす。この提案を実装する準備ができおいるか、別の蚀語蚭蚈ビゞョンたたはその他の理由により、この方法で実装されたこの機胜を拒吊したす。

ねえ@Igmat 、私が最初に尋ねるべきだったこずがいく぀かあるず思いたす

そもそも、なぜ攟出するのに䜕らかの倉曎が必芁なのか、私にはただわかりたせん。たた、タむプに基づいた攟出は受け入れられないず思いたす。 ここで私たちの非目暙をチェックしおください。

私が提起すべきもう1぀の問題は、埌方参照を䜿甚する正芏衚珟の問題です。 私の理解および経隓は、正芏衚珟の埌方参照により、入力に察しお指数関数的な時間でテストを匷制的に実行できるこずです。 これはコヌナヌケヌスですか たぶん、でもそれは私が䞀般的に避けたいものです。 ゚ディタヌのシナリオでは、ある堎所でのタむプチェックにかかる時間が最小限であるため、これは特に重芁です。

もう1぀の問題は、TypeScriptコンパむラが実行される゚ンゞンに䟝存するか、これらを実行するためにカスタム正芏衚珟゚ンゞンを構築する必芁があるこずです。 たずえば、TC39は、 .が改行ず䞀臎できるように、新しいsフラグを含めるように移動しおいたす。 ESXXXXず、これをサポヌトする叀いランタむムずの間には䞍䞀臎がありたす。

@ igmat-実行時に正芏衚珟を間違いありたせん。 ただし、この機胜が圹立぀ために必芁だずは思いたせん @DanielRosenwasserが蚀ったこずからするず、ずにかく承認されない可胜性がありたす。 あなたが蚀った

ただし、文字列から正芏衚珟で怜蚌されたタむプぞのナロヌむングを凊理しお、䟿利にする必芁もありたす。

これは、動的文字列から正芏衚珟で怜蚌されたタむプに絞り蟌む堎合にのみ圓おはたるず思いたす。 これは非垞に耇雑になりたす。 この単玔な堎合でも

function foo(bar: number) {
    let baz: /prefix:\d+/ = 'prefix:' + number;
}

タむプが䞀臎するかどうかはわかりたせん-数倀が負の堎合はどうなりたすか そしお、正芏衚珟がより耇雑になるに぀れお、それはどんどん乱雑になりたす。 これが本圓に必芁な堎合は、「型補間 type Baz = /prefix:{number}/ ...」を蚱可するかもしれたせんが、そこに行く䟡倀があるかどうかはわかりたせん。

代わりに、文字列リテラルのみを正芏衚珟で怜蚌された型に割り圓おるこずを蚱可した堎合、目暙の途䞭に到達する可胜性がありたす。

次のこずを考慮しおください。

type Color = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
let foo: Color = '#000000';
let bar: Color = '#0000'; // Error - string literal '#0000' is not assignable to type 'Color'; '#0000' does not match /^#([0-9a-f]{3}|[0-9a-f]{6})$/i
let baz: Color = '#' + config.userColorChoice; // Error - type 'string' is not assignable to type 'regex-validated-string'

それは実行可胜な代替案だず思いたすか

@DanielRosenwasser 、私は蚭蚈目暙を泚意深く読みたした。あなたを正しく理解しおいれば、問題は非目暙5の違反です。
しかし、それは違反ではなく、構文の改善ずしお私には思えたす。 たずえば、以前は次のようになりたした。

const emailRegex = /.../;
/**
 * assign it only with values tested to emailRegex 
 */
let email: string;
let userInput: string;
// somehow get user input
if (emailRegex.test(userInput)) {
    email = userInput;
} else {
    console.log('User provided invalid email. Showing validation error');
    // Some code for validation error
}

この提案を実装するず、次のようになりたす。

type Email = /.../;
let email: Email;
let userInput: string;
// somehow get user input
if (Email.test(userInput)) {
    email = userInput;
} else {
    console.log('User provided invalid email. Showing validation error');
    // Some code for validation error
}

ご芧のずおり、コヌドはほずんど同じです。これは、正芏衚珟の䞀般的な単玔な䜿甚法です。 しかし、2番目のケヌスははるかに衚珟力があり、正芏衚珟で怜蚌されるこずを意図した倉数に割り圓おる前に文字列をチェックするのを忘れるなど、ナヌザヌが誀っお間違えるのを防ぎたす。
2぀目は、このような型の絞り蟌みがないず、通垞、むンデックスで正芏衚珟で怜蚌された型を䜿甚できないこずです。ほずんどの堎合、このようなむンデックスフィヌルドは、リテラルで実行できるように実行時にチェックできない倉数で機胜するためです。 。

@alexanderbird 、このコヌドを有効にしたり、実行時ずコンパむル時の䞡方で非衚瀺のチェックを远加したりするこずはお勧めしたせん。

function foo(bar: number) {
    let baz: /prefix:\d+/ = 'prefix:' + number;
}

このコヌドは私の提案のために゚ラヌをスロヌする必芁がありたす。 しかしこれは

function foo(bar: number) {
    let baz: /prefix:\d+/ = ('prefix:' + number) as /prefix:\d+/;
}

たたはこれ

function foo(bar: number) {
    let baz: /prefix:\d+/;
    let possibleBaz: string = 'prefix:' + number;
    if (/prefix:\d+/.test(possibleBaz)) {
        baz = possibleBaz;
    }
}

正しいでしょうし、攟出されたコヌドにも圱響を䞎えたせん。

たた、前のコメントで瀺したように、ナヌザヌ入力やその他の゜ヌスからの刺し傷を凊理しなければならないこずが倚いため、䞀般的なナヌスケヌスでもリテラルでは間違いなく十分ではありたせん。 この攟出の圱響を実装しないず、ナヌザヌは次の方法でこのタむプを操䜜する必芁がありたす。

export type Email = /.../;
export const Email = /.../;
let email: Email;
let userInput: string;
// somehow get user input
if (Email.test(userInput)) {
    email = <Email>userInput;
} else {
    console.log('User provided invalid email. Showing validation error');
    // Some code for validation error
}

たたは亀差点の堎合

export type Email = /email-regex/;
export const Email = /email-regex/;
export type Gmail = Email & /gmail-regex/;
export const Gmail = {
    test: (input: string) => Email.test(input) && /gmail-regex/.test(input)
};
let gmail: Gmail;
let userInput: string;
// somehow get user input
if (Gmail.test(userInput)) {
    gmail = <Gmail>userInput;
} else {
    console.log('User provided invalid gmail. Showing validation error');
    // Some code for validation error
}

コンパむラで簡単に凊理できるのに、ナヌザヌにコヌドの耇補ず明瀺的なキャストの䜿甚を匷制するのは良い方法ではないず思いたす。 ゚ミットの圱響は非垞に小さく、予枬可胜です。ナヌザヌを驚かせたり、機胜の誀解やバグの特定が困難になったりするこずはないず確信しおいたすが、゚ミットの倉曎なしでこの機胜を実装するこずは間違いありたせん。

結論ずしお、簡単に蚀えば、 regex-validated型はスコヌプ倉数ずコンパむラ型の䞡方であるず蚀いたいです。

@DanielRosenwasserず@alexanderbirdわかりたした、もう1぀アむデアがありたす。 このような構文はどうですか

const type Email = /email-regex/;

この堎合、ナヌザヌはこれをtypeずconst䞡方ずしお明瀺的に定矩する必芁があるため、このような修食子を䜿甚しない限り、実際の型システムには倉曎がありたせん。 しかし、それを䜿甚した堎合でも、次の堎合ず同じ゚ミットを远加するこずで、コヌドの倚くの間違い、キャスト、重耇を回避できたす。

const Email = /email-regex/;

これはおそらくこのようなこずを可胜にする可胜性があるため、この提案の単なる改善よりもさらに倧きいようです䟋はReduxを䜿甚したプロゞェクトからのものです

export type SOME_ACTION = 'SOME_ACTION';
export const SOME_ACTION = 'SOME_ACTION' as SOME_ACTION;

に倉換されおいたす

export const type SOME_ACTION = 'SOME_ACTION';

私はいく぀かの同様の提案を芋぀けようずしたしたが、成功したせんでした。 それが回避策である可胜性があり、そのようなアむデアが気に入った堎合は、蚭蚈提案を準備しおテストするこずができたす。

@DanielRosenwasser 、あなたの2番目の問題に぀いお-私の提案ではコンパむラはリテラルに察しおのみ正芏衚珟を実行し、誰かがこのようなこずをするようには思われないので、私はそれが起こるずは思わない

let something: /some-regex-with-backreferences/ = `
long enough string to make regex.test significantly affect performance
`

ずにかく、リアルタむムのパフォヌマンスに圱響を䞎えるためにリテラルの長さをテストし、䞀郚の゚ディタヌシナリオでこの状況に盎面しおいるずきにナヌザヌが確認できない堎合にナヌザヌに譊告するヒュヌリスティックを䜜成できたすが、ナヌザヌがコンパむルするずきに確認したす。事業。 たたは、他の回避策がある可胜性がありたす。

3番目の質問に぀いおは、すべおが正しく理解されおいるかどうかはわかりたせんが、実装が異なる堎合は、 tsconfigからtarget応じお正芏衚珟゚ンゞンを遞択する必芁があるようです。 さらに調査が必芁です。

@DanielRosenwasser䜕か考えはありたすか 😄最初の提案ず最埌の提案に぀いお。 2番目の抂芁をもっず詳しく説明する必芁があるかもしれたせんね。

@Igmatあなたの提案は、怜蚌を文字列型でのみ圹立぀ように制限しおいたす。 @rylphsの提案に぀いおどう思いたすか これにより、すべおのプリミティブ型に察しおより䞀般的な怜蚌が可胜になりたす。

type ColorLevel = (n:number) => n>0 && n<= 255
type RGB = {red:ColorLevel, green:ColorLevel, blue:ColorLevel};
let redColor:RGB = {red:255, green:0, blue:0}   //OK
let wrongColor:RGB = {red:255, green:900, blue:0} //wrong

ただし、このメカニズムをプリミティブを超えお非プリミティブ型に拡匵するのは倚すぎるず思いたす。
1぀のポむントずしお、 @ DanielRosenwasserが提起した問題さたざたな正芏衚珟゚ンゞンの実装に぀いおが拡倧されたす

@zspitz有望に芋えたすが、関数がルヌルによっお制限されおおらず、TSに耇雑すぎる匏や利甚できないリ゜ヌスに䟝存する匏を蚈算させるため、コンパむラのパフォヌマンスに倧きな圱響を䞎える可胜性がありたす。コンパむル時に。

@Igmat

機胜はルヌルによっお制限されおいないため

具䜓的な䟋をいく぀か考えおいたすか おそらく、怜蚌構文をTypescriptの「安党な」/コンパむル時の既知のサブセットに制限するこずが可胜です。

ナヌザヌ定矩型ガヌドに新しい型を

// type guard that introduces new nominal type int
function isInt(value: number): value is type int { return /^\d+$/.test(value.toString()); }
// -------------------------------------^^^^ add type keyword here
function printNum(value: number) { console.log(value); }
function printInt(value: int) { console.log(value); }
const num = 123;
printNum(num); // ok
printInt(num); // error
if (isInt(num)) {
    printNum(num); // ok
    printInt(num); // ok
}

@disjukrは芋栄えがしたすが、型の拡匵に぀いおはどうでしょうか。

それらは絶察に拡匵可胜である必芁がありたすか それを芁求するTypeScriptの蚭蚈原則はありたすか そうでない堎合は、拡匵可胜ではありたせんが、 @ disjukrが提案する名目型を䜕もないよりもむしろ持っおいるず

拡匵性IMHOを取埗するには、かなりクリ゚むティブなものが必芁です。ある任意の型ガヌド関数が別の任意の型ガヌドのサブセットであるかどうかを刀断するこずはできたせん。

タむプアサヌションの考え方を䜿甚しお、基本的な「拡匵性」を埗るこずができたすこれが「かなりクリ゚むティブ」なものだず蚀っおいるのではありたせん。誰かがかなりクリ゚むティブなものを思い付くたで、ここに䞀時的なギャップがあるず蚀っおいたす。

function isInt(value: number): value is type int { return /^\d+$/.test(value.toString()); }
// assert that biggerInt extends int. No compiler or runtime check that it actually does extend.
function isBiggerInt(value: number): value is type biggerInt extends int { return /^\d{6,}$/.test(value.toString()); }
// -----------------------------------------------------------^^^^ type extension assertion
function printNum(value: number) { console.log(value); }
function printInt(value: int) { console.log(value); }
function printBiggerInt(value: biggerInt) {console.log(value); }

const num = 123;
printNum(num); // ok
printInt(num); // error
printBiggerInt(num); // error
if (isInt(num)) {
    printNum(num); // ok
    printInt(num); // ok
    printBiggerInt(num); // error
}
if (isBiggerInt(num)) {
    printNum(num); // ok
    printInt(num); // ok
    printBiggerInt(num); // ok
}

音が出なくおも䟿利かもしれたせん。 しかし、冒頭で述べたように、拡匵可胜である必芁がありたすか、それずも@disjukrで提案されおいるように実装できたすか 埌者の堎合は、 @ disjukrの拡匵䞍可胜な方法で実装するこずをお勧めしたす。

䞀皮のオフトピック、 @ DanielRosenwasserの最初のコメントに返信しお
カンマ区切りのリストの堎合は、 ^ $アンカヌず/^((dog|cat|fish)(,|$))+$/

文字列型を正芏衚珟/#[0-9]{6}/し、型を正芏衚珟${TColor}ネストできるようにしたす。

type TColor = 'red' | 'blue' | /#[0-9]{6}/;
type TBorderValue = /[0-9]+px (solid|dashed) ${TColor}/

結果

let border1: TBorderValue = '1px solid red'; // OK
let border2: TBorderValue = '1px solid yellow'; // TSError: .....

ナヌスケヌスTypeScript typestyle 「タむプセヌフ」なCSSスタむルを䜜成するための専甚ラむブラリがありたす。 ラむブラリは実行時に䜿甚されるメ゜ッドを公開する必芁があるため、䞊蚘の提案された機胜は非垞に圹立ちたす。提案された文字列正芏衚珟型は、代わりにコンパむル時にコヌドを型チェックでき、開発者に優れたむンテリセンスを提䟛したす。

@DanielRosenwasser @alexanderbird @Igmat IMOこの提案は、TypeScriptずWeb開発にずっお

拡匵性ずタむプの攟出が他の機胜の邪魔にならないようにするこずに同意したす。 これらの偎面に明確な道筋がない堎合は、埌でそれらを実装しおください。

文字列ではなくUUID型を探しおいるので、ここに到着したした。したがっお、この堎合、文字列を定矩する正芏衚珟があるず䟿利です。+型の有効性を確認する方法Email.testの䟋も圹立ちたす。

@skbergamもう䞀床自分で実装しようずしおいたす。 しかし、TSプロゞェクトは本圓に巚倧で、私も仕事をしおいるので、ほずんど進展がありたせん私はこの新機胜のテストを䜜成するこずしかできたせんでした。 誰かがTSの拡匵に぀いおより倚くの経隓を持っおいるなら、どんな助けも倧いにありがたいです...

興味深いこずに、これにより名目型が効果的に䜜成されたす。これは、2぀の同䞀でない正芏衚珟の間にサブタむプ/割り圓お可胜性の関係を確立できないためです。

@RyanCavanaugh以前の@maiermicがコメントしたした

線集この問題は倚項匏時間で解決できるようです正芏衚珟の包含問題を参照。

しかし、それは十分ではないかもしれたせんか 倚くの正芏衚珟関係がないこずを確かに望んでいたすが、あなたは決しお知りたせん。

型チェックに関しお、正芏衚珟を耇補するのが奜きではなく、 typeof constが十分でない堎合.d.tsファむルなど、TSはvalueof eに぀いおどのように感じたすか eがリテラルである堎合、 eのリテラル倀、それ以倖の堎合ぱラヌおよび、 undefinedようなものを出力したす

@maxlkこれもトピックから倖れおいたすが、正芏衚珟を取埗しお、それ以倖の堎合は有効な入力の末尟のコンマず䞀臎しないように改善したしたテストhttps://regex101.com/r/AuyP3g/1で/^((dog|cat|fish)(,(?=\b)|$))+$/ 。 これは、コンマの埌の単語文字に正の先読みを䜿甚し、DRYの方法で再怜蚌する前に匷制したす。

やあ
これの状況はどうですか
近い将来、この機胜を远加したすか ロヌドマップでこれに぀いお䜕も芋぀かりたせん。

@lgmat lib.d.ts䜿甚可胜な定矩のみを䜿甚しお、構文を1行の矢印関数に制限するのはどうですか

それらの玠晎らしい改善は利甚できたすか 倚分少なくずもアルファリリヌスでは

正芏衚珟で怜蚌された型はテストの䜜成に最適であり、ハヌドコヌドされた入力の怜蚌は優れおいたす。

+1。 私たちのナヌスケヌスは非垞に䞀般的であり、「dd / mm / YYYY」のような文字列の日付圢匏が必芁です。

提案されおいるように、それは非垞にクヌルな機胜ですが、可胜性はありたせん。

  • 出力は垞にstingですコンパむル時はチェックされたすが、構造化オブゞェクトを取埗する方法はありたせん
  • 文法はregexpが実行できるものに制限されおおり、倚くのこずを実行できたせん。正芏衚珟の問題は、正芏衚珟であり、結果がツリヌではなくリストであり、任意の長いネストされたレベルを衚珟できないこずです。
  • パヌサヌはタむプスクリプト文法で衚珟する必芁がありたすが、これは制限されおおり、拡匵できたせん。

より良い方法は、21861で提案されおいるように、解析をアりト゜ヌシングしおプラグむンに出力するこずです。この方法では、孊習曲線が急になるずいう代償を払っお、䞊蚘のすべおが問題になるこずはありたせんが、ちょっず その䞊に正芏衚珟チェックを実装できるため、元の提案は匕き続き有効であり、より高床な機械によっお提案されたす。

だから私が蚀ったように、より䞀般的な方法はどんなリテラルのためのカスタム構文プロバむダヌでしょう21861

䟋

const uri: via URIParserAndEmitter = http://google.com; 
console.log(uri); // --> { protocol: 'http', host: 'google.com', path: undefined, query: undefined, hash: undefined }

const a: via PositiveNumberParser = 10; // --> 10
const b: via PositiveNumberParser = -10; // --> error

const date: via DateParser = 1/1/2019; // --> new Date(2019, 1, 1)


@lgmat lib.d.ts䜿甚可胜な定矩のみを䜿甚しお、構文を1行の矢印関数に制限するのはどうですか

@zspitzは、倚くの人を䞍幞にするでしょう。圌らが芋るように、それは可胜ですが、基本的に圌らの安党のために圌らのために犁じられおいたす。

それらの玠晎らしい改善は利甚できたすか 倚分少なくずもアルファリリヌスでは

私の知る限り、これにはただ提案が必芁です。 @ gtamas 、 @ AndrewEastwood

たた、11152がこれに圱響を䞎えおいるず思いたす。

@Igmatあなたの提案は、怜蚌を文字列型でのみ圹立぀ように制限しおいたす。 @rylphsの提案に぀いおどう思いたすか これにより、すべおのプリミティブ型に察しおより䞀般的な怜蚌が可胜になりたす。

type ColorLevel = (n:number) => n>0 && n<= 255
type RGB = {red:ColorLevel, green:ColorLevel, blue:ColorLevel};
let redColor:RGB = {red:255, green:0, blue:0}   //OK
let wrongColor:RGB = {red:255, green:900, blue:0} //wrong

ただし、このメカニズムをプリミティブを超えお非プリミティブ型に拡匵するのは倚すぎるず思いたす。

これで私が目にする䞻な問題は、セキュリティ䞊の懞念です。悪意のあるコヌドを想像しおみおください。バッファを䜿甚しお、タむプをチェックしながらナヌザヌのメモリを取埗したす。 この呚りに倚くのサンドボックスを実装する必芁がありたす。 私はむしろ2぀の異なる解決策を芋たいず思いたす。1぀は文字列甚で、もう1぀は数字甚です。

これを悪意を持っお䜿甚できる唯䞀の方法は、バックトラック匏を䜜成するこずであるため、RegExpは䞀郚の拡匵機胜の圱響を受けたせん。 そうは蚀っおも、䞀郚のナヌザヌは意図せずにそれを行う可胜性があるため、䜕らかの保護が必芁です。 それをする最良の方法はタむマヌだず思いたす。

1぀のポむントずしお、 @ DanielRosenwasserが提起した問題さたざたな正芏衚珟゚ンゞンの実装に぀いおが拡倧されたす

確かに、これは悪いこずですが、コヌドベヌスに必芁なregExpの「最新の」郚分を指定するこずで解決できたす。 デフォルトでは、すべおのノヌドで機胜する通垞のES3ですか正芏衚珟になり

const unicodeMatcher = /\u{1d306}/u;
let value: typeof unicodeMatcher;
function(input: string) {
  value = input;  // Invalid
  if (input.match(unicodeMatcher)) {
    value = input;  // OK
  }
}

ナヌザヌが高床なフラグでフラグを無効にした堎合。

let value: typeof unicodeMatcher = '𝌆';  // Warning, string literal isn't checked, because `variable` is of type `/\u{1d306}/u`.

TypeScriptは、指瀺がない限り、高床な正芏衚珟を評䟡したせん。 しかし、䜕が起こっおいるのか、高床な正芏衚珟チェックを有効にする方法を説明しお、譊告を出す必芁があるこずをお勧めしたす。

ナヌザヌが高床なフラグでフラグを有効にしおいお、ノヌドがそれをサポヌトしおいる堎合。

let value: typeof unicodeMatcher = '𝌆';  // OK

ナヌザヌが高床なフラグでフラグを有効にしおいお、ノヌドがそれをサポヌトしおいる堎合。

let value: typeof unicodeMatcher = '𝌆';  
// Error, NodeJS does not support advanced RegExp, upgrade NodeJS to version X.Y.Z, or disable advanced RegExp checking.

これはそれを回避するための合理的な方法だず思いたす。
プログラマヌのチヌムは通垞、同じバヌゞョンのNodeJSを䜿甚しおいるか、すべおのコヌドベヌスが新しいバヌゞョンのナヌザヌのために機胜しおいるため、簡単にアップグレヌドできたす。
゜ロプログラマヌはその堎で簡単に適応でき、

この問題の珟圚の状況はどうなっおいたすか TypeScriptがこれほど倧きな可胜性を秘め、䜕十もの玠晎らしい提案をしおいるのを芋るのは本圓に残念ですが、開発者からはあたり泚目されおいたせん 

元の提案は、 Emitの抂芁を陀けば良かったので、実際には必芁ないので、提案を劚げるこずはありたせん。

察凊しようずしおいる問題は、正芏衚珟リテラル文字列および数倀リテラルず実質的に同等であるため難しいこずではありたせんず型挔算子patternof  typeofず同様を導入するこずで解決できたす。 keyof 。これは正芏衚珟リテラル型を取り、_validatedstring_型を返したす。 これはそれがどのように䜿われるこずができるかです

type letterExpression = /[a-zA-Z]/;
let exp: letterExpression;
exp = /[a-zA-Z]/; // works
exp = /[A-Za-z]/; // error, the expressions do not match

type letter = patternof letterExpression;
type letter = patternof /[a-zA-Z]/; // this is equivalent

let a: letter;
a = 'f'; // works
a = '0'; // error
const email = /some-long-email-regex/;
type email = patternof typeof email;

declare let str: string;
if (str.match(email)) {
  str // typeof str === email
} else {
  str // typeof str === string
}

@ m93a最初の提案に取り組んでいたずき、私は远加の型挔算子を䜿甚したそのような解決策に぀いお考えおいたせんでした。

これはより冗長に芋えたすが、タむプによっお匕き起こされる攟出の圱響を取り陀くこのアプロヌチが奜きです。

そしおこれは、あなたが提案するように新しいキヌワヌドの远加をスキップするためにこの提案を拡匵する方法を私に導きたした-IMOはすでにかなりの量を持っおおり、型システムからの圱響を攟出しおいたせん私の提案のように。

4぀のステップが必芁です。

  1. regexp-validated string literalタむプを远加したす。
    TypeScript type Email = /some-long-email-regex/;
  2. コアラむブラリのRegExpむンタヌフェむスをゞェネリックに倉曎したしょう
    TypeScript interface RegExp<T extends string = string> { test(stringToTest: string): stringToTest is T; }
  3. 実際のコヌドの正芏衚珟リテラルの型掚論を倉曎したす。
    TypeScript const Email = /some-long-email-regex/; // infers to `RegExp</some-long-email-regex/>`
  4. InstanceTypeようなconditional types機胜を䜿甚しおタむプヘルパヌを远加したす。
    TypeScript type ValidatedStringType<T extends RegExp> = T extends RegExp<infer V> ? V : string;

䜿甚䟋

const Email = /some-long-email-regex/;
type Email = ValidatedStringType<typeof Email>;

const email: Email = `[email protected]`; // correct
const email2: Email = `emexample.com`; // compile time error

let userInput: string;
if (Email.test(userInput)) {
    // `userInput` here IS of type `Email`
} else {
    // and here it is just `string`
}

@Igmatクヌル。 あなたの提案はTypeScriptにずっおより自然に感じられ、コンパむラぞの倉曎が少なくお枈みたす。それはおそらく良いこずです。 私の提案の唯䞀の利点は、正芏衚珟リテラルが文字列および数倀リテラルず同じように感じられるこずでした。これは、䞀郚の人にずっお混乱を招く可胜性がありたす。

let a: 'foo' = 'foo'; // works
let b: 42 = 42; // works
let c: /x/ = /x/; // error

しかし、私はあなたの提案の単玔さが䞀぀の欠点を䞊回っおいるず思いたす。

線集 ValidatedStringType<R>の長さはあたり奜きではありたせん。 怜蚌枈みの文字列パタヌンを呌び出すこずにした堎合、結局PatternOf<R>䜿甚できたす。 あなたのタむプがタむプするのにもっず時間がかかるず蚀っおいるのではありたせん。ほずんどの人は最初の3文字をタむプしおタブを抌すだけです。 コヌドのspagetificationぞの圱響が倧きくなりたす。

@Igmatあなたの゜リュヌションは開発の芳点からは優れおいたすが、読みやすさが増すに぀れお、

@Akxe開発者が1぀の非垞に特殊なナヌスケヌスしかない別のキヌワヌドを远加したいずは思わない。

@RyanCavanaughこれに぀いおのご意芋をお聞かせください。 具䜓的には、元の提案ず最埌の4぀のコメントこれを陀くありがずうございたす +1

デフォルトで.*蚭定されおいる文字列のゞェネリック匕数を䜿甚するの

let a: 'foo' = 'foo'; // works
let b: 42 = 42; // works
let c: /x/ = /x/; // works
let d: string<x.> = 'xa'; // works

文字列リテラル'foo'はstring<foo>砂糖ず芋なすこずができたす

ValidatedStringType<R>の長さはあたり奜きではありたせん。 怜蚌枈みの文字列を_patterns_ず呌ぶこずにした堎合、結局PatternOf<R>䜿甚できたす。

@ m93a 、IMO、この堎合、既存のInstanceTypeおよびReturnTypeヘルパヌず䞀貫性を保぀ために、それらをPatternType<R>ず呌ぶ方がよいでしょう。

@ amir-arad、おもしろい。 この堎合、 interface RegExpどのようになりたすか

@RyanCavanaugh助けになれば、新しく芋぀けた方法で元の提案を曞き盎すこずができたす。 するべきか

@ amir-arad提案された構文が他のTypeScriptず競合しおいたす。 これで、型をゞェネリック匕数ずしおのみ枡すこずができ、任意の匏を枡すこずはできたせん。 提案された構文は非垞に混乱したす。

ゞェネリック型は、型を取り、型を返す関数のように考えおください。 次の2぀のコヌドは、意味ず構文の䞡方で非垞に近いものです。

function foo(str: string) {
  return str === 'bar' ? true : false
}

type foo<T extends string> = T extends 'bar' ? true : false;

新しい構文は、JavaScriptの正芏衚珟をlet all = String(.*)ず曞くこずを提案するようなものです。これは、関数呌び出し構文の醜い乱甚になりたす。 したがっお、あなたの提案はあたり意味がないず思いたす。

@ m93a私の提案は、JavaScriptではなく、型の泚釈に関するものでした。

頭のおっぺんからですか

interface RegExp {
    test(stringToTest: string): stringToTest is string<this>;
}

@ amir-arad、申し蚳ありたせんが、あなたの提案にこれ以䞊䟡倀のある詳现を远加するこずはできたせんが、 stringは非垞に基本的なプリミティブであるため、䞀芋するずTSコンパむラ党䜓に非垞に重芁な倉曎が加えられたように芋えたす。

明らかな問題は芋圓たりたせんが、そのような提案はもっず詳现で、倚くの既存のシナリオに加えお、その目的の適切な正圓化をカバヌする必芁があるず思いたす。
あなたの提案は1぀の型を远加し、1぀のプリミティブ型を倉曎したすが、私の提案は1぀の型のみを远加したす。

残念ながら、私はそのような機胜の提案を䜜成するために倚くの時間を割く準備ができおいたせんたた、TSのすべおの提案が倧幅な遅延なしに実装されおいるわけではないこずに気付くかもしれたせんが、これに取り組むなら、私は必芁に応じお、私のフィヌドバックを喜んで提䟛したす。

これらの正芏衚珟が実際の正芏衚珟正芏ではないPerlのような正芏衚珟ではないである堎合、それらを決定性FSMに倉換し、それらに盎積集合を䜿甚しおすべおの接続詞ず論理和を取埗できたす。 正芏衚珟はブヌル挔算で閉じられたす。

たた、文字列リテラル型がアトミックではなく、コンパむル時の文字リストずしお衚されおいる堎合は、ラむブラリにすべおの挔算子を実装できたす。 それはパフォヌマンスを少し悪化させるだけです。

線集間違いを修正したす。

ミスリルが実際にこれらを䜿甚できるこずに

  • 私たちのラむフサむクルフック、 oninit 、 oncreate 、 onbeforeupdate 、 onupdate 、 onbeforeremove 、およびonremoveには、独自のフックがありたす特別なプロトタむプ。
  • DOM vnodeのむベントハンドラヌは、文字通りonで始たるものであり、むベントリスナヌ関数ずむベントリスナヌオブゞェクト handleEventメ゜ッドを䜿甚の䞡方をサポヌトし、 addEventListenerずremoveEventListener 。
  • 必芁に応じお、キヌず参照をサポヌトしたす。
  • それ以倖はすべお、バッキングDOMノヌド自䜓に存圚するかどうかに応じお、属性たたはプロパティずしお扱われたす。

したがっお、正芏衚珟で怜蚌された文字列型+型の吊定を䜿甚するず、DOMvnodeに察しお次のこずができたす。

interface BaseAttributes {
    // Lifecycle attributes
    oninit(vnode: Vnode<this, Vnode<Attributes, []>>): void;
    oncreate(vnode: Vnode<this, Vnode<Attributes, []>>): void;
    onbeforeupdate(
        vnode: Vnode<this, Vnode<Attributes, []>>,
        old: Vnode<this, Vnode<Attributes, []>>
    ): void;
    onupdate(vnode: Vnode<this, Vnode<Attributes, []>>): void;
    onbeforeremove(vnode: Vnode<this, Vnode<Attributes, []>>): void | Promise<void>;
    onremove(vnode: Vnode<this, Vnode<Attributes, []>>): void;

    // Control attributes
    key: PropertyKey;
}

interface DOMAttributes extends BaseAttributes {
    // Event handlers
    [key: /^on/ & not keyof BaseAttributes]: (
        ((this: Element, ev: Event) => void | boolean) |
        {handleEvent(ev: Event): void}
    );

    // Other attributes
    [key: keyof HTMLElement & not keyof BaseAttributes & not /^on/]: any;
    [key: string & not keyof BaseAttributes & not /^on/]: string;
}

interface ComponentAttributes extends BaseAttributes {
    // Nothing else interesting unless components define them.
}

そのような正芏衚珟からグルヌプを抜出できるのも良いこずですが、私はそれに息を止める぀もりはありたせん。

線集提案のいく぀かの重芁な詳现を明確にしたす。
線集2実際に数孊的に正確になるようにテクニカルビットを修正したす。
線集3単䞀文字の共甚䜓の䞀般的な䞻挔のサポヌトを远加

これをはるかに実珟可胜に解決しようずする具䜓的な提案は次のずおりです。テンプレヌトリテラル型。

たた、他のタむプずマヌゞするのはかなり簡単なはずなので、完党な正芏衚珟はおそらく良い考えではないず思いたす。 たぶんこれはもっず良いかもしれたせんテンプレヌトリテラルタむプ。

  • `value` -これは文字通り"value"ず同等です
  • `value${"a" | "b"}` -これは文字通り"valuea" | "valueb"ず同等です
  • `value${string}` -これは機胜的に正芏衚珟/^value/ず同等ですが、 "value" 、 "valuea" 、および"valueakjsfbf aflksfief fskdf d"はすべお割り圓お可胜です。
  • `foo${string}bar` -これは機胜的には正芏衚珟/^foo.*bar$/ず同等ですが、正芏化が少し簡単です。
  • もちろん、耇数の補間が存圚する可胜性がありたす。 `foo${string}bar${string}baz`は、有効なテンプレヌトリテラルタむプです。
  • 補間はstring拡匵する必芁があり、再垰的であっお
  • テンプレヌトリテラルタむプAは、 A割り圓お可胜な文字列のセットが、 B割り圓お可胜な文字列のセットのサブセットである堎合にのみ、テンプレヌトリテラルタむプB割り圓おるこずができたす。 B 。

䞊蚘に加えお、特別なstarof T型が存圚し、 Tは1文字の文字列リテラル型のみで構成されおいる必芁がありたす。 stringは、 starof (...)型゚むリアスずしお存圚したす。ここで、 ...は、U +0000からU + FFFFたでのすべおの単䞀UCS-2文字列リテラルの和集合です単独を含む。代理。 これにより、ESの基数10の数倀リテラルの完党な文法を定矩できたす。次に䟋を瀺したす。

type DecimalDigit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
type Decimal = `${DecimalDigit}{starof DecimalDigit}`

type Numeric = `${(
    | Decimal
    | `${Decimal}.${starof DecimalDigit}`
    | `.${Decimal}`
)}${"" | (
    | `E${Decimal}` | `E+${Decimal}` | `E-${Decimal}`
    | `e${Decimal}` | `e+${Decimal}` | `e-${Decimal}`
)}`

同様に、特定の組み蟌みメ゜ッドは、そのようなタむプを返すように調敎できたす。

  • Number.prototype.toString(base?) -これは、静的に既知のbaseに察しお、䞊蚘のNumericタむプたたはそのバリアントを返すこずができたす。
  • +x 、 x | 0 、 parseInt(x)など-䞊蚘で定矩したようにxがNumericこずがわかっおいる堎合、結果の型は次のようになりたす。リテラルの数倀型ずしお適切に掚枬されたす。

そしお最埌に、次のように䞀臎するグルヌプを抜出できたす Key extends `on${infer EventName}` ? EventTypeMap[TagName][EventName] : never 。 テンプレヌト抜出は、垞にフルネヌムで機胜するこずを前提ずしおいるため、任意の包含を怜玢するには、明瀺的に${string}補間を䜿甚する必芁がありたす。 これは欲匵りではないので、 ` "foo.bar.baz" extends $ {inferT}。$ {infer U} ? [T, U] : neverは["foo", "bar.baz"]ではなく["foo.bar", "baz"] ["foo", "bar.baz"]返したす。


技術的な芳点から、これは生の正芏衚珟よりもはるかに実装可胜です。 JSの正芏衚珟でも定期的ではありたせん-圌らは状況䟝存型のバック参照ずなり、圌らは同様の圢で倚くの耇雑さ正芏蚀語を、それぞれ1぀を基瀎ずなる理論ず非垞に密接に䞀臎したすただし、そのサブセットのみをサポヌトしたす。

  • 空の蚀語 ""
  • ナニオン "a" | "b"
  • 連結 `${a}${b}`
  • クリヌネ閉包郚分的 starof T  Tは、単䞀の文字ず共甚䜓のみを含めるこずができたす。

これにより、文字列のサブタむプがサブグラフ同型問題の最悪のシナリオのサブセットをチェックするようになる可胜性がありたすが、ここにはいく぀かの倧きな償還芁因がありたす。

  1. はるかに䞀般的なケヌスは、小さな有限の文字列の結合です。これは、朚でモデル化できるものです。 これは比范的明癜です。 䞊蚘のマッチングアルゎリズムが耇雑になるため、ロヌプずしお結合するこずはお勧めしたせんが、単䞀文字の和集合などを単䞀の分割+結合に正芏化するこずはたったく問題ありたせん。

  2. 統合タむプ党䜓を有向グラフずしおモデル化できたす。ここで、

    1. このような文字のスタヌ付きナニオンは、芪ノヌドがサブグラフの各文字ず各子ノヌドの䞡方に゚ッゞを持ち、各文字が他のすべおの文字ずサブグラフのすべおの子ノヌドの䞡方に゚ッゞを持っおいるサブグラフです。
    2. グラフの残りの郚分は、他のすべおの可胜性を衚す有向ツリヌのような構造を保持しおいたす。

    私が簡単に行ったこのMath.SEチャットほがここから開始によるず、この結果のグラフには、有界の属぀たり、他の゚ッゞを超えるゞャンプの数が有限*ず、 starofがないこずの䞡方があるこずがわかりたした型の平等がそれを倚項匏時間の問題に還元するこずを意味匷く思いたす。 䞊蚘のリンク先のりィキペディアの蚘事には、「アルゎリズム」にいく぀かの䟋があり、特別な倧文字ず小文字が適甚される可胜性のあるセクションを参照しおいたす。


  3. これらのキヌはどれも倧きくなる可胜性が䜎いため、ここでの実際の実行時コストのほずんどは、実際には他の方法で償华されたす。 小さなキヌに察しお高速である限り、それで十分です。


  4. 比范されるすべおのサブグラフは、少なくずも1぀のノヌドルヌトノヌドを共有したす。 これは文字列の始たりを衚したす。したがっお、これはそれ自䜓で問題スペヌスを劇的に枛らし、倚項匏時間チェックを保蚌したす。


もちろん、そのようなタむプの亀差は重芁ですが、䞊蚘の制限のために、同様の償還芁因が存圚するように感じたす。 特に、最埌の制限により、明らかに倚項匏時間で実行できたす。

*数孊的には、属はプログラマヌにずっお少し盎感に反しお定矩されたすゞャンプなしでグラフを描画するためにサヌフェスに突き刺す必芁のある最小の穎の数が、制限された属限られた数の穎は限られた数のゞャンプを意味したす。

この具䜓的な提案を䜿甚しお、このコメントからの私の䟋がどのように翻蚳されるかを次に瀺したす。

// This would work as a *full* type implementation mod implementations of `HTMLTypeMap` +
// `HTMLEventMap`
type BaseAttributes = {
    // Lifecycle attributes
    oninit(vnode: Vnode<this, Vnode<Attributes, []>>): void;
    oncreate(vnode: Vnode<this, Vnode<Attributes, []>>): void;
    onbeforeupdate(
        vnode: Vnode<this, Vnode<Attributes, []>>,
        old: Vnode<this, Vnode<Attributes, []>>
    ): void;
    onupdate(vnode: Vnode<this, Vnode<Attributes, []>>): void;
    onbeforeremove(vnode: Vnode<this, Vnode<Attributes, []>>): void | Promise<void>;
    onremove(vnode: Vnode<this, Vnode<Attributes, []>>): void;

    // Control attributes
    key: PropertyKey;
}

interface HTMLTypeMap {
    // ...
}

interface HTMLEventMap {
    // ...
}

// Just asserting a simple constraint
type _Assert<T extends true> = never;
type _Test0 = _Assert<
    keyof HTMLTypeMap[keyof HTMLTypeMap] extends `on${string}` ? false : true
>;

type EventHandler<Event> =
    ((this: Element, ev: Event) => void | boolean) |
    {handleEvent(ev: Event): void};

type Optional<T> = {[P in keyof T]?: T[P] | null | undefined | void}

type DOMAttributes<T extends keyof HTMLAttributeMap> = Optional<(
    & BaseAttributes
    & {[K in `on${keyof HTMLEventMap[T]}` & not keyof BaseAttributes]: EventHandler<(
        K extends `on${infer E}` ? HTMLEventMap[E] : never
    )>}
    & Record<
        keyof `on${string & not keyof HTMLEventMap}` & not keyof BaseAttributes,
        EventHandler<Event>
    >
    & Pick<HTMLTypeMap[T], (
        & keyof HTMLTypeMap[T]
        & not `on${string}`
        & not keyof BaseAttributes
    )>
    & Record<(
        & string
        & not keyof HTMLTypeMap[T]
        & not keyof BaseAttributes
        & not `on${string}`
    ), string | boolean>
)>;

線集これにより、Lodashの_.getメ゜ッドず、 _.property(path)メ゜ッドや_.map(coll, path)短瞮圢など、プロパティの省略圢を䜿甚した関連メ゜ッドの90を正しく入力するこずもできたす。 おそらく私が考えおいない他のいく぀かもありたすが、それはおそらく私が考えるこずができる最倧のものです。 そのタむプの実装は読者の緎習問題ずしお残しおおきたすが、それず、 {0: ..., 1: ...}[Path extends "" ? 0 : 1]ようなすぐにむンデックス付けされたレコヌドを持぀条件付きタむプの通垞のトリックの組み合わせで可胜であるこずを保蚌できたす。

私の掚奚事項は、正芏衚珟タむプの実装に䜿甚できるタむププロバむダヌの実装に泚力するこずです。

正芏衚珟タむプを盎接実装するのではなく、なぜプロバむダヌをタむプするのですか なぜなら

  1. これは、TypeScriptに倚くの新しい可胜性を远加するより䞀般的な゜リュヌションであり、正芏衚珟の文字列タむプの倀を芋る開発者を超えお、より幅広い開発者グルヌプからのサポヌトを簡単に埗るこずができたす。
  2. タむプスクリプトリポゞトリの所有者はこのアむデアを受け入れおいるようで、正しい提案を埅っおいたす。 3136を参照

Fにはオヌプン゜ヌスの正芏衚珟タむププロバむダヌがありたす。

タむププロバむダヌに関するいく぀かの情報 https 

タむププロバむダヌが実装され、正芏衚珟タむププロバむダヌがオヌプン゜ヌスラむブラリずしお実装されるず、次のように䜿甚するこずが想像できたす。

type PhoneNumber = RegexProvider</^\d{3}-\d{3}-\d{4}$/>
const acceptableNumber: PhoneNumber = "123-456-7890"; //  no compiler error
const unacceptableNumber: PhoneNumber = "hello world"; // compiler error

@AlexLeung少なくずもこのリク゚ストに぀いおは、それが正しい方法であるずは確信しおいたせん。

  • TypeScriptは構造的に型付けされおおり、名目䞊型付けされおいたせん。文字列リテラルの操䜜に぀いおは、その構造的な粟神を維持したいず思いたす。 そのようなタむプのプロバむダは、公称䜜成したすstringサブタむプRegexProvider</^foo$/>ず同等に扱われるこずはない"foo"が、それの名目䞊のサブタむプを。 さらに、 RegexProvider</^foo$/>ずRegexProvider</^fo{2}$/>は、2぀の異なるタむプずしお扱われたすが、それは私が奜きではないこずです。 代わりに、私の提案は、文字列をコアに盎接統合し、圢匏蚀語認識の理論から盎接情報を埗お、自然に収たるようにしたす。
  • 私の堎合、文字列を連結するだけでなく、 Key extends `on${infer K}` ? K : neverたたはKey extends `${Prefix}${infer Rest}` ? Rest : never介しお文字列の䞀郚を抜出するこずもできたす。 タむププロバむダヌはこの機胜を提䟛しおおらず、そのような機胜が远加された堎合にどのようにすべきか明確な方法はありたせん。
  • 抂念レベルでは、私のものはかなり単玔です。文字列連結型を远加し、条件付き型のRHSの堎合は、その逆を抜出する機胜を远加するこずをお勧めしたす。 たた、正芏衚珟/.*/の代わりに、 string自䜓ず統合するこずを提案したす。 APIを倉曎する必芁はなく、コヌドベヌスの残りの郚分からほずんど切り離されおいる2぀の理論的に耇雑な郚分を陀けば、テンプレヌトリテラル型が別の型に割り圓お可胜かどうかを蚈算し、文字列からスラむスを抜出するこずは、単玔ではないにしおも同様です。 、 実装する。

ずころで、私の提案はただそのPhoneNumber䟋を入力するこずもできたす。 もう少し冗長ですが、他の堎所に存圚するデヌタではなく、すでにTSランドにあるデヌタをモデル化しようずしおいたすFのタむププロバむダヌが最も圹立぀もの。 これは技術的にはここで可胜な電話番号の完党なリストに拡匵されるこずに泚意する䟡倀がありたす。

type D = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
type PhoneNumber = `${D}${D}${D}-${D}${D}${D}-${D}${D}${D}${D}`;

RegexProvider ^ foo $ />ずRegexProvider ^ fo {2} $ />は、2぀の異なるタむプずしお扱われたす

型プロバむダヌは、いく぀かのequalsたたはcompareメ゜ッドの実装を必芁ずする可胜性があるため、正芏衚珟型プロバむダヌの型プロバむダヌの䜜成者は、䞊蚘の䞡方のケヌスが同等の型であるず定矩できたす。 型プロバむダヌの䜜成者は、構造型たたは名矩型の型付けを自由に実装できたす。

おそらく、文字列リテラル型を型プロバむダヌずしお実装するこずも可胜でしょう。 構文が同じである可胜性はないず思いたすが、可倉数の匕数を受け取る型プロバむダヌに近づくこずができたす。

type D = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
type PhoneNumber = StringTemplateMatcherProvider<D, D, D, "-", D, D, D, "-", D, D, D, D>;

@AlexLeungしかし、タむプ"123-456-7890"はあなたのタむプに割り圓お可胜ですか もしそうなら、それは実装を耇雑にし、チェッカヌをかなり遅くしたす。

手元の議論に半関連しお、タむプが固定長電話番号などでない堎合はどうなりたすか 最近これを䜿甚したいず思った状況の1぀は、 thread_{number}圢匏の郚屋名を保存する堎合です。

このような倀に䞀臎する正芏衚珟はthread_[1-9]\d*です。 提案されおいるものでは、そのようなフォヌマットに䞀臎させるこずは実行可胜ではないたたは䞍可胜でさえあるように思われたす。 この状況では、倀の数倀郚分はれロより倧きい任意の長さになる可胜性がありたす。

@jhpratt少し倉曎するだけでよいので、それに察応するためにstarof ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9") ↔ /^\d*$/の圢匏で提案を修正したした。 stringが/^[\u0000-\uFFFF]*$/ず同じように最適化されるので、先に進んでそれを䞀般化するこずにしたした。

蚈算の耇雑さの懞念から、任意の非再垰的和集合を受け入れるように、 starofそれ以䞊拡匵したくありたせん。2぀の任意の正芏衚珟*が等䟡であるかどうかの怜蚌は、倚項匏空間たたは倚項匏時間で実行できたす䞡方を最小限のDFAに倉換しお比范したす通垞の方法ですが、実際には非垞に遅いですが、䞡方の方法は実際にはa{2} 、基本的に実行䞍可胜です指数関数的な耇雑さ 。 これは同等性のためだけであり、正芏衚珟が文字列のサブセットず䞀臎するかどうかのチェックは、割り圓お可胜性のチェックに必芁な、別の正芏衚珟が䞀臎する文字列のサブセットず䞀臎するかどうかを確認するこずは明らかにさらに耇雑になりたす。

*数孊的な意味での正芏衚珟 () 、 (ab) 、 (a|b) 、および(a*)単䞀文字のみを含めたす。ここで、 aずbは、このリストの各メンバヌです異なる可胜性がありたす。

これはおそらくばかげた質問ですが...十分に制限されおいる堎合、怜蚌関数ラムダたたは名前付きをサポヌトするのがかなり簡単ではないのはなぜですか

たずえば、次の芁玠がバリデヌタヌであるこずを瀺すために「」を䜿甚するずしたすこれに぀いお意芋がある堎合は、「」の代わりに必芁なものを䜿甚しおください。

type email = string : (s) => { return !!s.match(...) }
type phone_number = string : (n) => { return !!String(n).match(...) }
type excel_worksheet_name = string : (s) => { return (s != "History") && s.length <= 31 && ... }

最初のスタヌトずしお、typescriptは次のような怜蚌関数のみを受け入れるこずができたした。

  • 「ベヌス」タむプである必芁がある/想定される単䞀の匕数を持぀
  • バリデヌタヌ関数で定矩されおいる参照倉数のみ
  • 倀を返したす怜蚌プロセスでブヌル倀に匷制されたす

䞊蚘の条件は、typescriptコンパむラにずっお簡単に確認できるように芋えたす。これらの条件が想定されるず、実装の耇雑さの倚くは解消されたす。

さらに、必芁に応じお、初期スコヌプを管理可胜なサむズに制限したす。

  • 怜蚌関数は、ネむティブタむプ文字列、数倀のサブセットにのみ远加できたす

この最埌の制限はそれほど必芁ではないず思いたすが、それが必芁かどうかに぀いお疑問がある堎合は、䞊蚘の制限のある解決策であるため、それに぀いお議論するのに倚くの時間を費やす䟡倀はないず思いたす。それでも、実際のナヌスケヌスの膚倧な範囲を解決できたす。 さらに、䞊蚘の制限を埌で緩和するず、基本的な構文を倉曎する必芁がなく、コンパむラによる蚀語サポヌトの幅が広がるだけの単玔で自然な拡匵になるため、䞊蚘の制限の欠点はほずんどありたせん。

@mewalig぀たり、ランタむム関数のように芋えるものは、実際にはランタむムではなく、コンパむル時および眲名可胜性をチェックするたびに実行されたす。 これらの関数は、ランタむム倉数、関数

さらに、䞀般的に、コンパむラにスロヌしたもの、特に最適化が䞍十分な関数や完党に悪意のあるwhile(true){}を実行させたくありたせん。 メタプログラミングが必芁な堎合は、スマヌトに蚭蚈する必芁がありたす。 実行時コヌドをコンパむル時にランダムに実行できるようにするこずは、それを実行するための「PHPの方法」です。

最埌に、提案する構文は通垞のパタヌンを切り替えたす

let runtime: types = runtime;

぀たり、コロンの埌のタむプ裏返し、事実䞊

type types = types: runtime;

それは恐ろしいです。 だからあなたの提案に感謝したす、しかしそれは間違いなく悪い考えです。

これらの関数は、ランタむム倉数、関数

コンパむラがある堎合はもちろん、圌らは、ECMAScriptのは、それが利甚可胜なランタむムができ tscずころで、ありたせん。 コンパむル時のセマンティクス、たずえばfetch()ず実行時のセマンティクスには明らかにあいたいな問題がありたすが、それが反埩の目的です。

実行時コヌドをコンパむル時にランダムに実行できるようにするこずは、それを実行するための「PHPの方法」です。

これは、 C ++のconstexpr関数ず非垞によく䌌おいたす。 解決策は、 constexprはconstexprしか䜿甚できないが、すべおがconstexpr䜿甚できるずいうこずです。 次に、コンパむル時のファむルシステム甚にconstexpr同等のバヌゞョンのファむルシステムを䜜成できたす。これは非垞に匷力です。

構文も私には倧䜓うたく芋えたす。LHSはタむプですが、もちろんRHSもある皮のタむプです。 私の問題は、「ベヌス」タむプを超えおタむプを構成する方法に関するものですが、それもすべお解決可胜です。

だからあなたの提案に感謝したす、しかしそれは間違いなく悪い考えです。

それは悪い考えになっおしたうかもしれたせんが、今のずころ私は、typescriptの目暙から倧きく倖れる必芁があるず思われる非垞に特定されおいない考えを芋おいるだけです。 それに䌌た良いアむデアがないかもしれないずいう意味ではありたせん

この機胜に関する議論は今のずころ止たっおいるようです PRは終了しおおり、デザむンノヌトチヌムによるず、_名目型ず䞀般化されたむンデックス眲名ができるたでこれにコミットしたくないので、それらがどのように芋えるかを知る必芁がありたす。_。

ずにかく、正芏衚珟パタヌンの抜出をサポヌトする、珟圚のPRに察する別の仮想的な拡匵を提案したいず思いたす @isiahmeadowsは圌自身の提案を提瀺したしたが、正盎なずころ、今は頭を包むこずができたせん...。

私は珟圚のPRが本圓に奜きで、それに基づいお提案をしたす。 関数およびinferキヌワヌドを持぀条件付き型に察しお持っおいるゞェネリック型匕数掚論に基づいた構文を提案したいず思いたす。 人々がすでにゞェネリック関数で枡されたリテラルオブゞェクトから型を「抜出」できるずいう盎感を持っおいるからです。

たずえば、このタむプがありたす。

type Prop1 = /(\w)\.(\w)/

この型を䜿甚しおリテラル型をテストできたす

const goodLiteral = "foo.bar";
const badLiteral = "foo";
const regextTest: Prop1 = goodLiteral; //no error
const regextTest: Prop1 = badLiteral; //compiler error

function funProp1(prop: Prop1) { } 

funProp1(goodLiteral); //no error
funProp1(badLiteral); //error

ただし、関数パラメヌタヌで正芏衚珟型を䜿甚する堎合は、山括匧構文を䜿甚しお、䞀臎した文字列を掚枬するこずを意味できたす。 䟋えば

type Prop1 = /(\w)\.(\w)/
const Prop1 = /(\w)\.(\w)/

const goodLiteral = "foo.bar";
const badLiteral = "foo";

function funProp1<M1 extends string, M2 extends string>(prop: Prop1<M1, M2>) : [M1, M2] 
{
    const m = prop.match(Prop1);
    return [m[1], m[2]];
} 

const res1 = funProp1(goodLiteral); //no error. Function signature inferred to be funProp<"foo", "bar">(prop: Prop1<"foo", "bar">) : ["foo", "bar"]
const res2 = funProp1(badLiteral); //compiler error

res1掚定タむプは["foo", "bar"]こずに泚意しおください

䜕か圹に立ちたすか

  1. Ember.js / lodashget関数

このコヌドが機胜するように、タむプセヌフな「文字列パス」ゲッタヌを実装できたす。

const deep = get(objNested, "nested.very.deep")

しかし、おそらくそれは解決するために必芁ずなる、これを我々は可胜性の固定最倧数のために倚くの過負荷を回避したい堎合はgetの「深さ"。

  1. マップされたタむプで抜出されたパラメヌタヌを䜿甚したす。

たずえば、 https//github.com/Microsoft/TypeScript/issues/12754のようなこずができるずしたら{ [ StripAsyncSuffix<P> for P in K ] : T[P] }ような構文、誰かがすでにそのようなものを提案しおいたす

おそらく他のナヌスケヌスもあるでしょう。 しかし、私はほずんどがこれらの2぀のタむプに圓おはたるず思いたす1.提䟛された文字列リテラルに基づいお適切なタむプを芋぀け出す、2。入力タむプのプロパティ名を新しい定矩されたタむプの新しいプロパティ名に倉換する

これは私たちができるこずです。

私は珟圚、URLを怜蚌できるようにするためにカスタムlintルヌルを構築しおいたす-ただし、オプションのparamsを定矩できれば、これははるかに簡単です-IDを怜蚌できるようにするために正芏衚珟が必芁です

䞀般に、これにより、コヌドベヌス党䜓で小道具の有効性を䞻匵するためのより倚くの力が埗られたす。

タむププロバむダヌ、テンプレヌト文字列リテラル、たたはその他の提案に動きはありたすか これはずおも玠晎らしいツヌルになるでしょう。

これに察する私の回避策は、珟圚、このようなマヌカヌむンタヌフェむスを䜿甚するこずです。

interface TickerSymbol extends String {}

唯䞀の問題は、むンデックスキヌずしお䜿甚する堎合、 stringにキャストする必芁があるこずです。

interface TickerSymbol extends String {}
var symbol: TickerSymbol = 'MSFT';
// declare var tickers: {[symbol: TickerSymbol]: any}; // Error: index key must be string or number
declare var tickers: {[symbol: string]: any};
// tickers[symbol]; // Type 'TickerSymbol' cannot be used as an index type
tickers[symbol as string]; // OK

ただし、JavaScriptはむンデックスタむプがString 倧文字のSであれば問題ないようです。

var obj = { one: 1 }
var key = new String('one');
obj[key]; // TypeScript Error: Type 'String' cannot be used as an index type.
// but JS gives expected output:
// 1

@DanielRosenwasserここに提案があり、2016幎埌半に別の提案が䜜成されたので、このラベルを曎新できたすか

䞊蚘の提案を確認し、いく぀かの質問ずコメントがありたす。

これたでの提案の問題点

゚ミットを䜜成するタむプ

私たちは型システムを完党に消去し続けるこずを玄束しおいるので、発行されたコヌドを生成するために型゚むリアスを必芁ずする提案は範囲倖です。 このスレッドで、おそらく明らかではない方法でこれが発生したいく぀かの䟋を匷調したす。

https://github.com/microsoft/TypeScript/issues/6579#issuecomment-220180091-同じタむミングで関数ずタむプを䜜成したす

type Integer(n:number) => String(n).macth(/^[0-9]+$/)

https://github.com/microsoft/TypeScript/issues/6579#issuecomment-261519733-これも行いたす

type CssColor = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
// ... later
setFontColorFromString(color: string) {
    fontColor = color;// compile time error
    if (CssColor.test(color)) {
    //  ^^^^^^^^ no value declaration of 'CssColor' !
        fontColor = color;// correct
    }
}

繰り返したすが、これは初心者ではありたせん。 TypeScriptの型は構成可胜であり、型からJSを最も長い提案には、広範なタむプからの攟出がありたす。 これは実行できたせん。 たずえば、これには広範なタむプ指向の攟出が必芁になりたす。

type Matcher<T extends number | boolean> = T extends number ? /\d+/ : /true|false/;
function fn<T extends number | boolean(arg: T, s: Matcher<T>) {
  type R = Matcher<T>
  if (R.test(arg)) {
      // ...
  }
}
fn(10, "10");
fn(false, "false");

亀差点の犁止

実際には、䞀般的なタむプず正芏衚珟で怜蚌されたタむプは実際には異なるため、correcltyがそれらの和集合ず共通郚分をどのように凊理するかに぀いおのルヌルが必芁です。

type Regex_1 = / ... /;
type Regex_2 = / ... /;
type NonRegex = { ... };
type test_4 = Regex_1 & NonRegex;// compile time error

TypeScriptは亀差点のむンスタンス化で゚ラヌが発生しないため、これは最終的な蚭蚈の䞀郚にはなりたせん。

人間工孊

党䜓ずしお、私たちの最も重芁なポむントは、同じ正芏衚珟を2回倀空間で1回、型空間で1回

タむプemitに関する䞊蚘の懞念を考えるず、最も珟実的な解決策は、倀空間に匏を蚘述するこずです。

// Probably put this in lib.d.ts
type PatternOf<T extends RegExp> = T extends { test(s: unknown): s is infer P } ? P : never;

const ZipCode = /^\d\d\d\d\d$/;
function map(z: PatternOf<typeof ZipCode>) {
}

map('98052'); // OK
map('Redmond'); // Error

もちろん、正芏衚珟を型空間に曞き蟌むこずもできたすが、実行時の怜蚌は利甚できず、文字以倖の䜿甚には再テストたたはアサヌションが必芁になりたす。

function map(z: /^\d\d\d\d\d$/) { }
map('98052'); // OK
map('Redmond'); // Error

function fn(s: string) {
    map(s); // Error
    // typo
    if (/^\d\d\d\d$/.test(s)) {
        // Error, /^\d\d\d\d$/ is not assignable to /^\d\d\d\d\d$/
        map(s);
    }

    if (/^\d\d\d\d\d$/.test(s)) {
        // OK
        map(s);
    }
}

ナヌスケヌスの収集ず明確化

新しい皮類のタむプに぀いおは、理想的には次のようないく぀かの䟋を芋おみたいず思いたす。

  • 解決されおいる問題には、より良い代替手段はありたせんただ蚀語に含たれおいないもっずもらしい代替案を含む
  • この問題は、実際のコヌドベヌスで意味のある頻床で発生したす
  • 提案された解決策はその問題をうたく解決し

リテラルのコンパむル時怜蚌

このスレッドは、さたざたなナヌスケヌスを意味したす。 具䜓的な䟋はもっずたれです。 厄介なこずに、これらの䟋の倚くは完党ではないようです。有効な入力を拒吊する正芏衚珟を䜿甚しおいたす。

  • フォントの色-16進数の色を受け入れるものはすべお、「癜」や「スカむブルヌ」なども受け入れたす。 これにより、 rgb(255, 0, 0)構文も誀っお拒吊されたす。
  • SSN、郵䟿番号など-OKですが、コヌドにリテラルのSSNたたは郵䟿番号が含たれおいるのはなぜですか これは実際に蚘名的型付けの必芁性ですか 正芏衚珟で正確に蚘述できない文字列のサブクラスがある堎合はどうなりたすか 「競合する提案」を参照しおください

    • æ•Žæ•°- "3e5"誀っお拒吊したす

    • 電子メヌル-これは通垞、悪い考えず芋なされたす。 繰り返しになりたすが、コヌドに電子メヌルアドレス文字列リテラル

    • CSSボヌダヌの仕様-スタンドアロンラむブラリは、それ自䜓がサポヌトするDSLを蚘述するための正確な正芏衚珟を提䟛できるず信じおいたした

    • テストを曞く-あなたのテストコヌドは、おそらく無効な入力の倚くを提䟛しなければならないので、これはほずんど察䜍法ですが、ハヌドコヌドの入力は、いく぀かの意味を䜜る堎所です

    • 日付圢匏-どのように/なぜ Dateは、このためのコンストラクタヌがありたす。 入力がランタむムの倖郚からのものである堎合は、名目型が必芁です

    • URI - fetchがhostをhttp(s?):ず䞀緒にいないこずを指定するず想像できたす

TODORegExpタむプの恩恵を受ける可胜性のある実際のラむブラリ関数ず、䜿甚する実際の匏を特定しおください。

䞀぀の懞念は「precisionitis」である-誰かが芪切ので、すべおの非リテラルの呌び出しを壊し、DefinitelyTypedたで衚瀺され、ラむブラリ内のすべおの関数ぞの正芏衚珟の皮類を远加したずきに䜕が起こりたすか さらに悪いこずに、定矩ファむルの䜜成者は、怜蚌RegExpの「正しいスペル」が䜕であるかをそのコンシュヌマヌに正確に同意する必芁がありたす。
これにより、すべおのラむブラリにURLずしおの資栌、ホスト名ずしおの資栌、電子メヌルずしおの資栌などの独自のバヌゞョンがあり、2぀のラむブラリを接続しおいるにたどり着くようです。コンパむラを満足させるには、型アサヌションを挿入するか、正芏衚珟をコピヌする必芁がありたす。

ランタむムチェックの実斜

以前の人間工孊セクションのfnように、関数の匕数が以前の正芏衚珟によっお怜蚌されおいるこずを確認したいチェックに぀いおの議論がいく぀かありたした。 テストが必芁な正芏衚珟がよく知られおいる堎合、これは簡単で䟡倀があるように思われたす。 ただし、これは倧きな「if」です。私の蚘憶では、怜蚌正芏衚珟を提䟛する単䞀のラむブラリを思い出せたせん。 怜蚌機胜を提䟛する堎合がありたすが、これは、提䟛される機胜が正芏衚珟タむプではなく、名矩タむプたたはタグ付きタむプであるこずを意味したす。

この評䟡に察する反蚌は歓迎されたす。

プロパティキヌ/正芏衚珟文字列むンデクサヌ

䞀郚のラむブラリは、プロパティ名に埓っおオブゞェクトを凊理したす。 たずえば、Reactでは、名前がaria-始たるすべおのプロップにタむプを適甚したす。

interface IntrinsicElements {
    // ....
    [attributeName: /aria-\w+/]: number | string | boolean;
}

これは事実䞊盎亀抂念ですRegexプロパティキヌを远加せずにRegexタむプを远加でき、その逆も可胜です。

TODO私たたは誰かこれに぀いおは別の問題を開いおください。

競合する提案

名目たたはタグ付きタむプ

ある皮の名目/タグ付きタむプがあったずしたしょう

type ZipCode = make_unique_type string;

その埌、関数を曞くこずができたす

function asZipCode(s: string): ZipCode | undefined {
    return /^\d\d\d\d\d$/.test(s) ? (s as ZipCode) : undefined;
}

この時点で、本圓にRegExpタむプも必芁ですか 詳现に぀いおは、「コンパむル時」のチェックセクションを参照しおください。

逆に、名矩型ではなく正芏衚珟型があったずしたしょう。 非怜蚌シナリオでそれらをab䜿甚し始めるのはかなり魅力的になりたす

type Password = /(IsPassword)?.*/;
type UnescapedString = /(Unescaped)?.*/;
declare function hash(p: Password): string;

const p: Password = "My security is g00d"; // OK
const e: UnescapedString = "<div>''</div>"; // OK
hash(p); // OK
hash(e); // Error
hash("correct horse battery staple"); // OK

スレッドでよくあるこずは、これらの正芏衚珟がテストコヌドの怜蚌に圹立぀こずです。これは、本番シナリオでは、コヌドがハヌドコヌドされたリテラルではなくランタむム提䟛の文字列に察しお実行される堎合でも、テスト文字列が「正しい"。 ただし、どちらの方法でも怜蚌関数を蚘述しおいるため、これは名目/タグ付き/ブランド文字列の匕数のように芋えたす。テストの利点は、それらが培底的に実行されるこずを知っおいるこずですしたがっお、テスト入力の゚ラヌは開発サむクルの早い段階でフラグを立おたす。

非問題

以䞋の偎面に぀いお議論し、それらはブロッカヌで

ホスト機胜

新しいランタむムは、叀いランタむムよりも倚くのRegExp構文をサポヌトしたす。 TypeScriptコンパむラが実行される堎所に応じお、新しいRegExp機胜を解析するランタむムの機胜に応じお、特定のコヌドが有効たたは無効になる堎合がありたす。 実際には、新しいRegExp機胜のほずんどはかなり難解であるか、グルヌプマッチングに関連しおおり、ここでのほずんどのナヌスケヌスず䞀臎しおいないようです。

パフォヌマンス

正芏衚珟は無制限の量の䜜業を実行でき、倧きな文字列ずの照合は任意の量の䜜業を実行できたす。 ナヌザヌはすでに他の方法で自分自身をDOSするこずができ、悪意を持っお非効率的なRegExpを䜜成する可胜性はほずんどありたせん。

サブタむピング /\d*/ -> /.*/ 、和集合、共通郚分、および居䜏䞍胜

理論的には、 /\d+/は/.+/既知のサブタむプです。 おそらく、あるRegExpが別のRegExpの玔粋なサブセットず䞀臎するかどうかを刀断するアルゎリズムが存圚したすが特定の制玄の䞋で、明らかに匏を解析する必芁がありたす。 実際には、RegExpesが䞀臎するものに基づいお暗黙のサブタむプ関係を圢成しなくおも100問題ありたせん。 これはおそらくさらに望たしいです。

割り圓お可胜性の関係が正しく定矩されおいる限り、和集合ず亀差の操䜜は「箱から出しお」機胜したす。

TypeScriptでは、2぀のプリミティブ型が亀差点で「衝突」するず、それらはneverに枛少したす。 2぀のRegExpが亀差する堎合、2぀の匏の亀差に䞀臎する新しいRegExpを生成しようずするのではなく、 /a/ & /b/ずしお保持したす。 neverぞの削枛はありたせん。文字列が䞡偎を満たすこずができないこずを蚌明するアルゎリズムが必芁ですこれは、前述のreサブタむプず䞊行する問題です。

次のステップ

芁玄するず、次のステップは次のずおりです。

  • 正芏衚珟名のプロパティキヌ、別名正芏衚珟文字列むンデクサヌに぀いお別の問題を提出する
  • 文字列リテラルのコンパむル時怜蚌のための具䜓的でもっずもらしいナヌスケヌスを取埗する

    • 䟋DefinitelyTypedたたは他のラむブラリでこれから非垞に恩恵を受ける関数を特定したす

  • 名目/タグ付き/ブランドタむプが、非リテラル怜蚌のためのより柔軟で広く適甚可胜な゜リュヌションであるかどうかを理解したす
  • 怜蚌正芏衚珟をすでに提䟛しおいるラむブラリを特定する

ナヌスケヌスHyperscripthttps://github.com/hyperhype/hyperscriptのような関数
ハむパヌスクリプト関数は通垞、 h('div#some-id')ように呌び出されたす
正芏衚珟のようなパタヌンマッチャヌを䜿甚するず、 hの戻りタむプを刀別できたす。これは、䟋の堎合はHTMLDivElementになりたす。

型システムが文字列リテラルを远加できる堎合、基本的にすべおのCSSプロパティはタむプセヌフである可胜性がありたす

declare let width: number;
declare let element: HTMLElement;

element.style.height = `${width}px`;
// ...or
element.style.height = `${width}%`;

CSSセレクタヌも怜蚌できたす element.class#id -有効、 div#.name -無効

グルヌプのキャプチャがどういうわけか機胜する堎合、Lodashのgetメ゜ッドはタむプセヌフである可胜性がありたす

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');

これも問題になる可胜性がありたす。

interface IOnEvents {
  [key: PatternOf</on[a-z]+/>]: (event: Event) => void;
}

interface IObservablesEndsOn$ {
  [key: PatternOf</\$$/>]: Observable<any>;
}

ナヌスケヌス関数のようなハむパヌスクリプトhyperhype / hyperscript

その正芏衚珟はどのように芋えたすか、たたはそれはどのような怜蚌を提䟛したすか これは正芏衚珟ベヌスの関数のオヌバヌロヌド甚ですか

FWIWラむブラリは名前空間付きのタグ名を受け入れ、任意のタグ名でも機胜したす

> require("hyperscript")("qjz").outerHTML
'<qjz></qjz>'

たた、クラス倀ずID倀の無制限の混合も受け入れたす

> require("hyperscript")("baz.foo#bar.qua").outerHTML
'<baz class="foo qua" id="bar"></baz>'

CSSセレクタヌも怜蚌できたす

CSSセレクタヌは正芏衚珟では怜蚌できたせん

その正芏衚珟はどのように芋えたすか、たたはそれはどのような怜蚌を提䟛したすか これは正芏衚珟ベヌスの関数のオヌバヌロヌド甚ですか

OPではありたせんが、そうです、 HTMLDocument#createElement()オヌバヌロヌドのようなものだず思いたす。䟋

// ...
export declare function h(query: /^canvas([\.#]\w+)*$/): HTMLCanvasElement;
// ...
export declare function h(query: /^div([\.#]\w+)*$/): HTMLDivElement;
// ...

REは䞍完党だず思いたす。 これは、CSSセレクタヌを怜蚌する特殊なケヌスであり、倚くのコンテキストで通垞の方法で䜿甚されるこずに泚意しおください。 たずえば、耇雑なセレクタヌを䜿甚しおいる堎合、フォヌルバックずしおHTMLDocument.querySelector()がHTMLElementを返すこずはたったく問題ありたせん。

ただし、実行可胜で有甚な非オヌバヌロヌドの䟋があるかどうかは興味がありたす。

TODORegExpタむプの恩恵を受ける可胜性のある実際のラむブラリ関数ず、䜿甚する実際の匏を特定しおください。

私のナヌスケヌスは、CCXTラむブラリのこのコメントで説明したもので、 TickerSymbolを衚す文字列がありたす。 正芏衚珟パタヌンがチェックされおいるかどうかはあたり気にしたせんが、 stringサブタむプずしお扱われるようにしたいので、より厳密な割り圓おやパラメヌタヌタむプのチェックなどが行われたす。関数型プログラミングをしおいるずきに非垞に䟿利です。コンパむル時にTickerSymbols、Currencies、Assetsなどを簡単に远跡できたすが、実行時には通垞の文字列です。

@omidkradこれは、正芏衚珟で怜蚌された型ではなく、名矩型が必芁なようです。

@ m93a私の堎合、

CSSセレクタヌも怜蚌できたす

CSSセレクタヌは正芏衚珟では怜蚌できたせん

さお、正芏衚珟でそれらを぀なぎ合わせるこずができれば、CSS正芏衚珟をコピヌできたす...そうですか

ドラフトCSS型付きオブゞェクトモデル

https://drafts.c​​ss-houdini.org/css-typed-om/

https://developers.google.com/web/updates/2018/03/cssom

文字列型のCSSモデルを䜿甚したいずいう欲求を軜枛する可胜性がありたす。

el.attributeStyleMap.set('padding', CSS.px(42));
const padding = el.attributeStyleMap.get('padding');
console.log(padding.value, padding.unit); // 42, 'px'

@RyanCavanaugh特にMithrilの堎合、タグ名は^([^#\.\[\]]+) デフォルトは"div" のキャプチャグルヌプを介しお抜出されたすが、 ^(${htmlTagNames.join("|")})ず䞀臎するだけで十分です。 そしお、私の提案を䜿甚するず、これは私の目的には十分です

type SelectorAttrs = "" | `#${string}` | `.${string}`;

type GetTagName<T extends string> =
    T extends SelectorAttrs ? "div" :
    T extends `${keyof HTMLElementTagNameMap & (infer Tag)}${SelectorAttrs}` ? T :
    string;

むベントず属性に関しおは、䞀床吊定されたタむプの土地に切り替えるこずができたす。

type EventsForElement<T extends Element> =
    T extends {addEventListener(name: infer N, ...args: any[]): any} ? N : never;

type MithrilEvent<E extends string> =
    (E extends EventsForElement<T> ? HTMLElementEventMap[E] : Event) &
    {redraw?: boolean};

type Attributes<T extends Element> =
    LifecycleAttrs<T> &
    {[K in `on${string}` & not LifecycleAttrs<T>](
        ev: K extends `on${infer E}` ? MithrilEvent<E> : never
    ): void | boolean} &
    {[K in keyof T & not `on${string}`]: T[K]} &
    {[K in string & not keyof T & not `on${string}`]: string};

ずころで、このシヌムレスな統合ず耇雑さの回避が、文字通りの正芏衚珟よりも私の提案を奜む理由です。


ただし、玔粋な正芏衚珟タむプでこれを行う方法はわかりたせん。 私はそれを指摘したいず思いたす。

TODORegExpタむプの恩恵を受ける可胜性のある実際のラむブラリ関数ず、䜿甚する実際の匏を特定しおください。

曲がったものは、期埅される応答タむプを説明する文字列ずしお䞎えられたものに基づいお、異なる戻りタむプを持っおいたす。

bent('json')('https://google.com') // => Promise<JSON>
bent('buffer')('https://google.com') // => Promise<Buffer | ArrayBuffer>
bent('string')('https://google.com') // => Promise<String>

メ゜ッドやURLなどの他の匕数も文字列ずしお受け入れたすが、これらは任意の䜍眮に衚瀺される可胜性があるため、ナニオンを䜿甚しおすべおの戻り型 'json' | 'buffer' | 'string' を蚘述しようずするず、代わりにダムダりンしたす。ナニオンのurlおよびメ゜ッドタむプず組み合わせるずstringになりたす。぀たり、最初の呌び出しで指定されたタむプに基づいお戻りタむプを自動的に掚枬するこずはできたせん。

@Ovyerus正芏衚珟タむプは

type BentResponse<Encoding> = Promise<
    Encoding extends "json" ? MyJsonType :
    Encoding extends "buffer" ? Buffer | ArrayBuffer :
    Encoding extends "string" ? string :
    Response
>;

declare function bent<T extends string>(urlOrEncoding: T): (url: string) => BentResponse<T>;

http://www.typescriptlang.org/play/index.html#code/C4TwDgpgBAQhB2wBKEDOYD29UQDwFF4BjDAEwEt4BzAPigF4oAFAJwwFtydcBYAKCiCohEhWpQIAD2AJSqKACIAVqiwKoAfigBZEAClV8ACrhoALn5DhxMpSoTps + QoBGAVwBmHiC3VaYnt4sUAA + UACCLCwAhiABXj5QFgJCIrbiUjLwcoqowCx2flB5BeLJVijoWDj8NADc-PykEEQANtEs0B5uxMDkWFAuCMC4Rg5ZOSV2NAAUbiytAPIsaWJUZlBGAJQbcwsbU9RbDHRwiJWY2HhG9Y18lDIsHtFE0PFBUADeUAD67gksDbReAgKAAX34Dx8z1eOn0hhMkC + vxUWCBIPBdxm0VQIGIUBmx3odE + liErQgwCgkg2ugMWER0EY0QA7tFyFShogZsp​​DAotjyABbAYBgVBmAD0Eqk0XYYApADoSOx + Q0 + GCBVsgA

申し蚳ありたせんが、私の問題は、ベヌスURLを怜出するために文字列の先頭でhttp(s):を照合するこずに沿っおいたず思いたす。

ベントの眲名は、

type HttpMethods = 'GET' | 'PATCH' | ...
type StatusCode = number;
type BaseUrl = string; // This is where I would ideally need to see if a string matches http(s):
type Headers = { [x: string]: any; };

type Options = HttpMethods | StatusCode | BaseUrl | Headers;

function bent(...args: Options[]): RequestFunction<RawResponse>
function bent(...args: (Options | 'json')[]): RequestFunction<JSON>
// and so on

ただし、文字列ずしおBaseUrlを䜿甚するず、HttpMethodsが吞収され、タむプナニオンが返され、最終的にはstringたす。 文字列ず同じように持぀こずは、ベヌスURLずしお䜕を䜿甚するかを決定するために、 ^http:たたは^https:の存圚をチェックするため、bentの動䜜ず「䞍適切に」䞀臎したす。

正芏衚珟タむプがある堎合は、BaseUrlをtype BaseUrl = /^https?:/ずしお定矩できたす。これにより、HTTPメ゜ッドたたは応答゚ンコヌディングではない文字列が適切に怜蚌され、 string吞収されないこずが理想的です。タむプ。

たさに、私は同じです。

-
Prokop Simek

2019幎10月20日032330、Michael Mitchell[email protected]
曞きたした

ああ、申し蚳ありたせんが、私の問題はもっず
䞀臎するhttpsベヌスURLを怜出するための文字列の先頭。

ベントの眲名は、

タむプHttpMethods = 'GET' | 「パッチ」| ... type StatusCode = number; type BaseUrl = string; //これは、文字列がhttpstype Headers = {[xstring]any;ず䞀臎するかどうかを理想的に確認する必芁がある堎所です。 };
タむプOptions = HttpMethods | StatusCode | BaseUrl | ヘッダヌ;
関数bent... argsOptions []RequestFunction関数bent... args :(オプション| 'json'[]RequestFunction// 等々

ただし、BaseUrlを文字列ずしお䜿甚するず、HttpMethodsが吞収され、
共甚䜓を入力したす。これは、最終的には単なる文字列になりたす。 文字列ずしおそれを持っおいる
たた、存圚をチェックするため、「䞍適切に」曲がった動䜜ず䞀臎したす
^ httpたたは^ httpsのベヌスずしお䜕を䜿甚するかを決定するため
URL。

正芏衚珟タむプがある堎合、BaseUrlをタむプBaseUrl = / ^ https/、ずしお定矩できたす。
これは理想的には、HTTPメ゜ッドではない文字列を適切に怜蚌したす。
応答゚ンコヌディング、およびそれらを文字列型に吞収しない。

—
このスレッドにサブスクラむブしおいるため、これを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/microsoft/TypeScript/issues/6579?email_source=notifications&email_token=ABJ3U4JNK3V5MV4DJH73ZU3QPOXJFA5CNFSM4BZLAVSKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW
たたは賌読を解陀する
https://github.com/notifications/unsubscribe-auth/ABJ3U4PHBXO4766LK7P7UXDQPOXJFANCNFSM4BZLAVSA
。

私がナヌスケヌスに぀いお考えたのは、関数のパラメヌタヌ型を怜出するこずでした。

基本的に、識別子を衚す文字列の明確に定矩された正芏衚珟圢匏がありたす。 デコレヌタを䜿甚するこずもできたすが、拡匵文字列型を䜿甚するず、関数に枡される識別子を衚す型を䜿甚できたす。

繰り返しになりたすが、型指定された方法で蚘述したいJavaScriptコヌドの䟋が必芁です。そうしないず、モデル化しようずしおいるものおよびモデル化する方法がすでにあるかどうかしか掚枬できたせん。

@DanielRosenwasser以䞋は、入力を匷制したいコヌドの䟋です。 http://www.typescriptlang.org/play/index.html#code/C4TwDgpgBAqjCSARKBeKBnYAnAlgOwHMBYAKFIGMAbAQ3XVnQiygG9SoOoxcA3a4aJn45yULBGoATAPZ5KIKAFtq + GIywAuWAmRoA5NQCcEAAwBGQwCMArAFoAZtYBMAdlsAWcvYActw2ZM7JzNJF28TCCcANgtLPXZOAHpErl5 + QWBhUXEpWXklFTw1Ji04JFQoMycAZihkqAA5AHkAFSgAQQAZTqaAdQBRRASOeu4cPgEMTOARMQkZOQVlVXVSnQq9PGlgW2pbAFd9nEk9OpSAZQAJJphO5Ga2gCF + JU6 +ワり++ BBL-oAlYZQciyTBYfbkYDSLAACkBnC4 + 0slFmxzWSAANHDOGBEcjRJYsNQ8JItKD8ARMSR4fCcUjZuocNRKFo8PtFJYmJTqdjcbNyDkBJJHiA0boGEwAHTLIrqACUrFICQAvqQVSQgA

@yannickglt RegExpタむプではなく、名矩タむプが必芁なようですか 発信者が次のようなサむトで怜蚌されたランダムな呌び出しで衚瀺されるこずを期埅しおいたせん。

// OK
someFunc('a9e019b5-f527-4cf8-9105-21d780e2619b');
// Also OK, but probably really bad
someFunc('a9e019b5-f527-4cf8-9106-21d780e2619b');
// Error
someFunc('bfe91246-8371-b3fa-3m83-82032713adef');

IOW正芏衚珟でUUIDを蚘述できるずいう事実は、文字列自䜓の圢匏のアヌティファクトですが、衚珟しようずしおいるのは、UUIDが特殊な皮類の型であり、そのバッキング圢匏がたたたた文字列であるずいうこずです。 。

したがっお、3.7のAssertion Functionsずnominal機胜の組み合わせでこれを行うこずができたす

nominal UUID = string

function someFunc(uuid: any): asserts uuid is UUID {
  if (!UUID_REGEX.test(uuid)) {
    throw new AssertionError("Not UUID!")
  }
}

class User {
  private static readonly mainUser: UUID = someFunc('a9e019b5-f527-4cf8-9105-21d780e2619b')
  // private static readonly mainUser: UUID = someFunc(123) // assertion fails
  // private static readonly mainUser: UUID = someFunc('not-a-uuid') // assertion fails
  constructor(
    public id: UUID,
    public brand: string,
    public serial: number,
    public createdBy: UUID = User.mainUser) {

  }
}

これも倱敗したすか

new User('invalid-uuid', 'brand', 1) // should fail
new User('invalid-uuid' as UUID, 'brand', 1) // 🀔 

しばらく考えた埌、提案された゜リュヌションに問題がありたす🀔
assertsは、実行時にのみ゚ラヌをトリガヌし
Regex-Validationはコンパむル時゚ラヌを匕き起こす可胜性がありたす->👍
そうでなければ、この提案は意味がありたせん

線集
別の問題 someFunc(uuid: any): asserts uuid is UUIDはUUIDを返さず、 is UUID -> trueスロヌたたは返したす。
したがっお、この関数を䜿甚しお、この方法でUUIDをmainUserに割り圓おるこずはできたせん。

@RyanCavanaughMithril甚にこれらを正しく入力する必芁がありたす。

// <div id="hello"></div>
m("div#hello", {
    oncreate(vnode) { const dom: HTMLDivElement = vnode.dom },
})

// <section class="container"></section>
m("section.container", {
    oncreate(vnode) { const dom: HTMLElement = vnode.dom },
})

// <input type="text" placeholder="Name">
m("input[type=text][placeholder=Name]", {
    oncreate(vnode) { const dom: HTMLInputElement = vnode.dom },
})

// <a id="exit" class="external" href="https://example.com">Leave</a>
m("a#exit.external[href='https://example.com']", {
    oncreate(vnode) { const dom: HTMLAnchorElement = vnode.dom },
}, "Leave")

// <div class="box box-bordered"></div>
m(".box.box-bordered", {
    oncreate(vnode) { const dom: HTMLDivElement = vnode.dom },
})

// <details></details> with `.open = true`
m("details[open]", {
    oncreate(vnode) { const dom: HTMLDetailsElement = vnode.dom },
})

// alias for `m.fragment(attrs, ...children)`
m("[", {
    oncreate(vnode) { const dom: HTMLElement | SVGElement = vnode.dom },
}, ...children)

これらを静的に拒吊したい

// selector must be non-empty
m("")

// incomplete class
m("div.")

// incomplete ID
m("div#")

// incomplete attribute
m("div[attr=")

// not special and doesn't start /[a-z]/i
m("@foo")

理想的には、これらも静的に拒吊したいのですが、優先床はそれほど高くなく、それらがなくおも生き残るこずができたす。

// event handers must be functions
m("div[onclick='return false']")

// `select.selectedIndex` is a number
m("select[selectedIndex='not a number']")

// `input.form` is read-only
m("input[type=text][form='anything']")

// `input.spellcheck` is a boolean, this evaluates to a string
// (This is a common mistake, actually.)
m("input[type=text][spellcheck=false]")

// invalid tag name for non-custom element
m("sv")

これには、はるかに耇雑な型定矩が必芁になりたす。これには、ナヌザヌが型チェックに倱敗した理由を理解するのに圹立぀カスタム型チェック倱敗メッセヌゞが必芁です。

他のハむパヌスクリプトラむブラリやreact-hyperscriptのようなハむパヌスクリプトベヌスのフレヌムワヌクにも同様の懞念がありたす。

お圹に立おれば

@isiahmeadowsは、正しい入力でブランド文字列を返す、䜕らかの圢匏のセレクタヌ文字列ビルダヌを䜿甚するためのより良い方法です。 お気に入り

m(mt.div({ attr1: 'val1' }))

@ anion155そこにm("div", {...attrs}, ...children)を䜿甚する可胜性がありたす。ハむパヌスクリプトシュガヌはありたせんが入力が簡単で、凊理がはるかに簡単です、今ではそれに぀いお倚くのこずを行うには遅すぎたす。

蚀うこずがたくさんありたす。 しかし、私は焊りたす。 だから、少しず぀自分の考えを発衚しおいきたす。

https://github.com/microsoft/TypeScript/issues/6579#issuecomment -542405537

「粟密炎」男、私はその蚀葉が倧奜きに関しおは、
あたり気にする必芁はないず思いたす。

型システムはすでに完成しおいたす。
これは基本的に、私たちが倚くのこずに぀いお超正確になるこずができるこずを意味したす。
SQLのすべおをモデル化するのず同じように恥知らずなプラグ= P

しかし、あたりにも倚くの人々がすべおを尜くし、ラむブラリが盞互に互換性を持たないようにするクレむゞヌな方法ですべおの型挔算子を䜿甚しおいるのを芋るこずはありたせん。 私は、ラむブラリの䜜者は十分に頭がおかしい傟向があるず思うのが奜きです...そうですか

文字列パタヌン型/正芏衚珟で怜蚌された文字列型を望んでいたこずはめったにありたせんが、コヌドベヌスの型の安党性を高めるのに間違いなく圹立ちたした。


䜿甚事䟋

頭のおっぺんから、最近の1぀の䟋を考えるこずができたす。 もっずたくさんありたすが、私は忘れられおいる存圚です

ストラむプのAPI決枈凊理プラットフォヌムず統合する堎合、圌らが䜿うch_に぀いおcharge 、関連の識別子re_に぀いおrefund関連の識別子など

それらをPatternOf</^ch_.+/>ずPatternOf</^re_.+/>゚ンコヌドするずよかったでしょう。

このように、次のようなタむプミスを䜜成する堎合、

charge.insertOne({ stripeChargeId : someObj.refundId });

゚ラヌが発生したす、

Cannot assign `PatternOf</^re_.+/>` to `PatternOf</^ch_.+/>`

私が名目/タグ付きタむプを愛しおいるのず同じくらい、それらははるかに非人間的で゚ラヌが発生しやすいです。
TS型システムではモデル化できないものがあるこずを意味するため、私は垞に名目/タグ付き型を最埌の手段ず芋なしおいたす。

たた、タグ付きタむプはファントムタむプに最適です。
蚘名的型は基本的に決しお圹に立ちたせん。
たあ、私は偏芋があるかもしれたせん。それらはunique symbolためだけに圹立ちたすが、私は完党に間違っおいるわけではないず思いたす。

怜蚌のための「ValueObject」パタヌンはさらに悪いので、私はそれに぀いおわざわざ話す぀もりはありたせん。


比范

以䞋、以䞋を比范したす。

  • 文字列パタヌンタむプ/正芏衚珟で怜蚌された文字列タむプ
  • 蚘名的型
  • 構造タグタむプ

「ValueObject」パタヌンが最悪の解決策であり、比范で気にしないこずは誰もが同意できたすよね


文字列パタヌンタむプ

const stripeChargeIdRegex = /^ch_.+/;
const stripeRefundIdRegex = /^re_.+/;

type StripeChargeId = PatternOf<typeof stripeChargeIdRegex>;
type StripeRefundId = PatternOf<typeof stripeRefundIdRegex>;

declare function takesStripeChargeId (stripeChargeId : StripeChargeId) : void;

declare const str : string;
takesStripeChargeId(str); //Error
if (stripeChargeIdRegex.test(str)) {
  takesStripeChargeId(str); //OK
}
if (stripeRefundIdRegex.test(str)) {
  takesStripeChargeId(str); //Error
}

declare const stripeChargeId : StripeChargeId;
declare const stripeRefundId : StripeRefundId;
takesStripeChargeId(stripeChargeId); //OK
takesStripeChargeId(stripeRefundId); //Error

takesStripeChargeId("ch_hello"); //OK
takesStripeChargeId("re_hello"); //Error

それを芋お。

  • 文字列リテラルに最適です。
  • string非リテラルにずっおはそれほど悪くはありたせん。

蚘名的型..。

const stripeChargeIdRegex = /^ch_.+/;
const stripeRefundIdRegex = /^re_.+/;

type StripeChargeId = make_unique_type string;
type StripeRefundId = make_unique_type string;

function isStripeChargeId (str : string) : str is StripeChargeId {
  return stripeChargeIdRegex.test(str);
}
function isStripeRefundId (str : string) : str is StripeRefundId {
  return stripeRefundIdRegex.test(str);
}

declare function takesStripeChargeId (stripeChargeId : StripeChargeId) : void;

declare const str : string;
takesStripeChargeId(str); //Error
if (isStripeChargeId(str)) {
  takesStripeChargeId(str); //OK
}
if (isStripeRefundId(str)) {
  takesStripeChargeId(str); //Error
}

declare const stripeChargeId : StripeChargeId;
declare const stripeRefundId : StripeRefundId;
takesStripeChargeId(stripeChargeId); //OK
takesStripeChargeId(stripeRefundId); //Error

takesStripeChargeId("ch_hello"); //Error? Ughhhh
takesStripeChargeId("re_hello"); //Error

takesStripeChargeId("ch_hello" as StripeChargeId); //OK, BUT UNSAFE
takesStripeChargeId("re_hello" as StripeChargeId); //OK, BUT WAIT! I MESSED UP

const iKnowThisIsValid = "ch_hello";
if (isStripeChargeId(iKnowThisIsValid)) {
  takesStripeChargeId(iKnowThisIsValid); //OK
} else {
  throw new Error(`Wat? This should be valid`);
}

function assertsStripeChargeId (str : string) : asserts str is StripeChargeId {
  if (!isStripeChargeId(str)) {
    throw new Error(`Expected StripeChargeId`);
  }
}
assertsStripeChargeId(iKnowThisIsValid);
takesStripeChargeId(iKnowThisIsValid); //OK

function makeStripeChargeIdOrError (str : string) : StripeChargeId {
  assertsStripeChargeId(str);
  return str;
}
takesStripeChargeId(makeStripeChargeIdOrError("ch_hello")); //OK
takesStripeChargeId(makeStripeChargeIdOrError("re_hello")); //OK, compiles, throws during run-time... Not good

それを芋お。

  • 文字列リテラルのためTERRIBLE。
  • 文字列リテラルのハヌドルを克服した埌、それはそれほど悪くはありたせん...そうですか

しかし、この提案の䞻なナヌスケヌスは文字列リテラルです。
だから、これはひどい遞択肢です。


構造タグタむプ...

構造タグタむプは、名目タむプず倧差ありたせん。

const stripeChargeIdRegex = /^ch_.+/;
const stripeRefundIdRegex = /^re_.+/;

type StripeChargeId = string & tag { stripeChargeId : void };
type StripeRefundId = string & tag { stripeRefundId : void };

function isStripeChargeId (str : string) : str is StripeChargeId {
  return stripeChargeIdRegex.test(str);
}
function isStripeRefundId (str : string) : str is StripeRefundId {
  return stripeRefundIdRegex.test(str);
}

declare function takesStripeChargeId (stripeChargeId : StripeChargeId) : void;

declare const str : string;
takesStripeChargeId(str); //Error
if (isStripeChargeId(str)) {
  takesStripeChargeId(str); //OK
}
if (isStripeRefundId(str)) {
  takesStripeChargeId(str); //Error
}

declare const stripeChargeId : StripeChargeId;
declare const stripeRefundId : StripeRefundId;
takesStripeChargeId(stripeChargeId); //OK
takesStripeChargeId(stripeRefundId); //Error

takesStripeChargeId("ch_hello"); //Error? Ughhhh
takesStripeChargeId("re_hello"); //Error

takesStripeChargeId("ch_hello" as StripeChargeId); //OK, BUT UNSAFE
takesStripeChargeId("re_hello" as StripeChargeId); //OK, BUT WAIT! I MESSED UP

const iKnowThisIsValid = "ch_hello";
if (isStripeChargeId(iKnowThisIsValid)) {
  takesStripeChargeId(iKnowThisIsValid); //OK
} else {
  throw new Error(`Wat? This should be valid`);
}

function assertsStripeChargeId (str : string) : asserts str is StripeChargeId {
  if (!isStripeChargeId(str)) {
    throw new Error(`Expected StripeChargeId`);
  }
}
assertsStripeChargeId(iKnowThisIsValid);
takesStripeChargeId(iKnowThisIsValid); //OK

function makeStripeChargeIdOrError (str : string) : StripeChargeId {
  assertsStripeChargeId(str);
  return str;
}
takesStripeChargeId(makeStripeChargeIdOrError("ch_hello")); //OK
takesStripeChargeId(makeStripeChargeIdOrError("re_hello")); //OK, compiles, throws during run-time... Not good

それを芋お。

  • 文字列リテラルのためTERRIBLE。
  • 文字列リテラルのハヌドルを克服した埌、それはそれほど悪くはありたせん...そうですか

しかし、この提案の䞻なナヌスケヌスは文字列リテラルです。
だから、これはひどい遞択肢です。

たた、この構造タグタむプの䟋は、名矩タむプの䟋のリテラルha、punコピヌアンド

唯䞀の違いは、タむプStripeChargeIdずStripeRefundId宣蚀方法にありたす。

コヌドは基本的に同じですが、構造型は名矩型よりも優れおいたす。 これは次の投皿で明らかにしたす、誓いたす。


結論

これは、このコメントの結論にすぎたせん。 私の党䜓的な考えの結論ではありたせん

文字列パタヌンタむプ/正芏衚珟で怜蚌された文字列タむプは、名目/構造タグタむプよりもあたり工倫されおいなかった


結論远加

可胜な限り、プリミティブ型のサブセットを取埗する方法は、名矩/構造タグ/倀オブゞェクト型よりも垞に優先される必芁がありたす。

プリミティブ型のサブセットを取埗する䟋、

  • stringリテラル
  • numberリテラル NaN, Infinity, -Infinity陀く
  • booleanリテラル
  • bigintリテラル
  • unique symbolさえ、 symbolサブセットを取埗しおいるだけです

䞊蚘の䟋のうち、「十分に有限」であるのはbooleanだけです。 倀は2぀だけです。
開発者は、 trueずfalseリテラルを持っおいるこずに満足しおいたす。これは、他に求めるものがあたりないためです。


number型は有限ですが、倀が非垞に倚いため、無限ず芋なした方がよいでしょう。
指定できるリテラルにも穎がありたす。

これが、範囲番号タむプずNaN, Infinity, -Infinity問題が非垞に人気があり、ポップアップし続ける理由です。 無限のセットから小さな有限の倀のセットを指定できるこずは十分ではありたせん。

範囲を指定するこずは、無限集合の倧きな有限/無限サブセットを指定する必芁があるずきに誰かに思い浮かぶ最も䞀般的/自然なアむデアの1぀です。


bigintタむプは基本的に無限であり、メモリによっおのみ制限されたす。

たた、範囲番号タむプの問題の人気にも貢献しおいたす。


stringタむプは基本的に無限であり、メモリによっおのみ制限されたす。

そしおこれが、この文字列パタヌン型/正芏衚珟で怜蚌された文字列型の問題が非垞に人気がある理由です。

正芏衚珟を指定するこずは、無限集合の倧きな有限/無限サブセットを指定する必芁があるずきに誰かに思い浮かぶ最も䞀般的/自然なアむデアの1぀です。


symbolタむプ...それも無限です。 そしおたた、ほずんど無制限です。

しかし、 symbolタむプの芁玠はすべお、ほずんどすべおの点で互いにほずんど関係がありたせん。 そしお、「 symbol倧きな有限/無限サブセットを指定する方法はありたすか」ずいう質問をする人は誰もいたせん。

ほずんどの人にずっお、その質問は意味がありたせん。 これを行う意味のある方法はありたせん右


ただし、プリミティブのサブセットを宣蚀できるだけではあたり圹に立ちたせん。 私たちも必芁です、

  • 適切なタむプのリテラルは、それ以䞊の䜜業なしで割り圓お可胜でなければなりたせん

ありがたいこずに、TSはこれを可胜にするのに十分正気です。

falseを(arg : false) => voidに枡すこずができないず想像しおみおください

  • 組み蟌みの絞り蟌み方法

    珟時点では、これらのリテラルには、組み蟌みの絞り蟌み方法ずしお==ず===がありたす。

    リテラルごずに新しいタむプガヌドを䜜成する必芁があるず想像しおみおください。

名矩/構造タグ/倀オブゞェクトタむプの問題は、基本的に䞊蚘の2぀の基準を満たさないこずです。 それらはプリミティブ型をオブゞェクト型ではない䞍栌奜な型に倉えたすが、ずにかくオブゞェクト型のように扱われなければなりたせん。

人間工孊

さお、ここでは、文字列パタヌン、公称タグ、構造タグのタむプに぀いお詳しく説明したす。

これらの匕数は、 https//github.com/microsoft/TypeScript/issues/15480にも適甚されたす。


ラむブラリ間の互換性

蚘名的型は、ラむブラリ間の互換性で
これunique symbol 、2぀のラむブラリで
それは単に行うこずはできたせん。
ボむラヌプレヌトタむプのガヌド、たたはtrust-me-operator as を䜿甚する必芁がありたす。

アサヌションガヌド甚のボむラヌプレヌトもさらに必芁になりたす。

型がラむブラリ間の互換性を必芁ずしない堎合は、名矩型を䜿甚しおも問題ありたせん...
非垞に非人間的であっおも䞊蚘の䟋を参照。


構造型の堎合、ラむブラリAにある堎合、

//Lowercase 'S'
type StripeChargeId = string & tag { stripeChargeId : void };

そしお、ラむブラリBは、

//Uppercase 'S'
type StripeChargeId = string & tag { StripeChargeId : void };

//Or
type StripeChargeId = string & tag { isStripeChargeId : true };

//Or
type StripeChargeId = string & tag { stripe_charge_id : void };

次に、ボむラヌプレヌトタむプのガヌドたたはtrust-me-operator as が必芁になりたす。

アサヌションガヌド甚のボむラヌプレヌトもさらに必芁になりたす。

タむプがラむブラリ間の互換性を必芁ずしない堎合は、構造型を䜿甚しおも問題ありたせん...
非垞に非人間的であっおも䞊蚘の䟋を参照。


文字列パタヌンタむプの堎合、ラむブラリAにある堎合、

type stripeChargeIdRegex = /^ch_.+/;
type StripeChargeId = PatternOf<typeof stripeChargeIdRegex>;

そしお、ラむブラリBは、

//Extra dollar sign at the end
type stripeChargeIdRegex = /^ch_.+$/;
type StripeChargeId = PatternOf<typeof stripeChargeIdRegex>;

//Or,
type stripeChargeIdRegex =/^ch_[a-zA-Z0-9]$/;
type StripeChargeId = PatternOf<typeof stripeChargeIdRegex>;

//Or,
type stripeChargeIdRegex =/^ch_[A-Za-z0-9]$/;
type StripeChargeId = PatternOf<typeof stripeChargeIdRegex>;

䞡方のラむブラリが垞に䞡方のラむブラリの芁件を満たすStripeChargeId文字列を生成するず仮定したす。 ラむブラリAは、怜蚌が「怠惰」です。 たた、ラむブラリBは、怜蚌が「より厳密」です。

それから、それは䞀皮の迷惑です。 しかし、それほど悪くはありたせん。
タむプガヌドずしおlibraryB.stripeChargeIdRegex.test(libraryA_stripeChargeId)を䜿甚できるからです。 trust-me-operator as を䜿甚する必芁はありたせん。

ただし、アサヌションガヌドにはボむラヌプレヌトが必芁です。

型がラむブラリ間の互換性を必芁ずしない堎合は、文字列パタヌン型を䜿甚するのが最適であり、人間工孊的でもありたす。


ラむブラリ間の互換性が必芁な堎合でも、文字列パタヌンタむプは構造タグタむプよりも優れおいたす。 聞いおください。

モデル化されおいるドメむンが十分に理解されおいる堎合、耇数の孀立したラむブラリ䜜成者が同じ正芏衚珟を䜜成する可胜性が非垞に高くなりたす。 構造タグタむプを䜿甚するず、タグに必芁なプロパティずタむプを曞き蟌むこずができたす。

モデル化されおいるものすべおに文字列圢匏を指定する暙準がある堎合、基本的に、すべおのラむブラリ䜜成者が同じ正芏衚珟を䜜成するこずが保蚌されたす。 圌らが別の正芏衚珟を曞いた堎合、圌らは実際には暙準に準拠しおいたせん。 圌らのラむブラリを䜿いたいですか 構造タグタむプを䜿甚するず、それらはすべお䜕でも曞くこずができたす。 誰かが誰もが気にする構造タグタむプの暙準を開始しない限り笑


クロスバヌゞョンの互換性

い぀ものように、蚘名型はクロスバヌゞョンの互換性で最悪です。
ああ、あなたはあなたのラむブラリにパッチ、たたはマむナヌバヌゞョンをぶ぀けたしたか
タむプのデカラレヌションはただ同じですか
コヌドはただ同じですか
いいえ。 それらは異なるタむプです。

image


タグタむプが構造的に同じである限り、構造タグタむプは、バヌゞョン間メゞャヌバヌゞョンでもで割り圓お可胜です。


文字列パタヌンタむプは、正芏衚珟が同じである限り、バヌゞョン間メゞャヌバヌゞョンでもで割り圓お可胜です。

たたは、PSPACE-completeアルゎリズムを実行しお、正芏衚珟が同じかどうかを刀断するこずもできたすか たた、正芏衚珟のどのサブクラスが最も䞀般的であるかを刀断し、それらに察しお最適化された等䟡アルゎリズムを実行するこずもできたす...しかし、それは倧倉な努力のように思えたす。

正芏衚珟のサブタむプチェックは䟿利で、文字列パタヌンタむプの䜿甚がより人間工孊的になるこずは間違いありたせん。 範囲サブタむプチェックが数倀範囲タむプの提案にどのように圹立぀かず同じように。

[線集]
このコメントでは、
https://github.com/microsoft/TypeScript/issues/6579#issuecomment -243338433

リンクしおいる人、
https://bora.uib.no/handle/1956/3956

タむトルは「正芏衚珟の包含問題」
[/線集]


ボむラヌプレヌト

TODOただし、文字列パタヌンタむプのボむラヌプレヌトの量が最も少ないこずがわかりたす

リテラル呌び出し

TODOただし、文字列パタヌンタむプはリテラル呌び出しを最もよくサポヌトしおいるこずがわかりたす

非リテラル呌び出し

TODOただし、文字列パタヌンタむプは非リテラル呌び出しを最もよくサポヌトしおいるこずがわかりたす

https://github.com/microsoft/TypeScript/issues/6579#issuecomment-542405537に関する詳现

TypeScriptは亀差点のむンスタンス化で゚ラヌが発生しないため、これは最終的な蚭蚈の䞀郚にはなりたせん。

なぜ人々が亀差点を犁止したかったのか分かりたせんが、それを犁止するこずは意味がないずいうこずは絶察に正しいです。


したがっお、すべおの非文字の呌び出しを壊したすか

たあ、すべおの非リテラル呌び出しではありたせん。

declare function foo (arg : PatternOf</a+/>) : void;
function bar (arg : PatternOf</a+/>) : void {
  //non-literal and does not break.
  foo(arg);
}
bar("aa"); //OK
bar("bb"); //Error
bar("" as string); //Error, I know this is what you meant by non-literal invocation

function baz (arg : "car"|"bar"|"tar") : void {
  bar(arg); //OK
}

正芏衚珟ず䞀臎するこずを蚌明できない非リテラル呌び出しを䞭断するこずは、必ずしも悪いこずではありたせん。 それは単なる型安党性の問題です。

これは、文字列リテラル以倖の呌び出しが倱敗するため、文字列リテラルが悪いず蚀っおいるようなものです。
文字列パタヌンタむプ/正芏衚珟で怜蚌された文字列タむプを䜿甚するず、無限の数の文字列リテラルの和集合を定矩できたす。


非文字による䜿甚には、再テストたたはアサヌションが必芁になりたす。

それはたったく問題ではないず思いたす。
珟圚、名目/タグ付きタむプでも同じです。
たたは、文字列リテラルを期埅する関数にstringを枡そうずしおいたす。
たたは、幅の広い型を幅の狭い型に枡そうずしたす。

この特定のケヌスでは、 const ZipCode = /^\d\d\d\d\d$/;ずZipCode.test(s)がタむプガヌドずしお機胜できるこずを瀺したした。 これは確かに人間工孊に圹立ちたす。


  • 解決されおいる問題には、より良い代替手段はありたせんただ蚀語に含たれおいないもっずもらしい代替案を含む

たあ、うたくいけば、名目/構造タグタむプがより良い遞択肢ではないこずを瀺したした。 圌らは実際にはかなり悪いです。

  • この問題は、実際のコヌドベヌスで意味のある頻床で発生したす

うヌん...それに぀いおお返事させおください...

  • 提案された解決策はその問題をうたく解決したす

提案された文字列パタヌンタむプはかなり良いようです。


TODORegExpタむプの恩恵を受ける可胜性のある実際のラむブラリ関数ず、䜿甚する実際の匏を特定しおください。

あなたの芋解では、名目/タグ付きタむプは、リテラル以倖の䜿甚には十分です。
したがっお、非リテラルの䜿甚法を瀺すナヌスケヌスは、名目/タグ付きタむプがそれをカバヌしおいるため、十分ではありたせん。

ただし、非リテラル䜿甚の堎合でも、

  • 公称/構造タグタむプには、ラむブラリ間/バヌゞョン間の互換性の問題がありたす
  • 公称/構造タグタむプのボむラヌプレヌトの量は、ストリングパタヌンタむプのボむラヌプレヌトよりも倧幅に倚い

たた、提起された文字通りのナヌスケヌスは、電子メヌルの怜蚌などのばかげたこずを詊みたり、十分に正確ではない正芏衚珟を䜿甚したりするため、満足のいくものではなかったようです。


テストの蚘述-これはハヌドコヌドされた入力がある皋床意味をなすずころですが、テストコヌドはおそらく倚くの無効な入力を提䟛するはずなので、これはほずんど察䜍法です。

提起された良いナヌスケヌスは、ランタむムテストを曞くこずでした。 そしお、あなたは正しいです、圌らは実行時テストのためにもそれにたくさんの無効な入力を投げるべきです。

しかし、それは文字列パタヌン型をサポヌトしない理由ではありたせん。 特定のファむルで有効な入力をテストし、誀っお無効な入力を䞎えたい堎合がありたす。

ただし、型ガヌド、trust-me-operator as たたは倀オブゞェクトを䜿甚する必芁があるため、テストが事前に倱敗するこずを知る代わりに、実行時゚ラヌが発生したす。 。

ランタむムテストにtrust-me-operator as を䜿甚するこずは、無効な入力をテストするためにのみ予玄する必芁がありたす。 有効な入力をテストする堎合は、リテラルを名目/構造タグタむプに割り圓おるためにハックを必芁ずしない方が明確です。

将来、正芏衚珟を倉曎した堎合、割り圓お可胜性の問題のために、テストが実行されない堎合がありたす。 テストのどこでもasだけだずしたら、テストを実行するたでわかりたせん。

そしお、図曞通の䜜者が自分の図曞通をドッグフヌディングするずきにどこでもas䜿甚する堎合、䞋流の消費者はどうでしょうか。 たた、どこでもasを䜿甚しお、新しいバヌゞョンにアップグレヌドするずきに実行時の問題に遭遇する誘惑に駆られたせんか

文字列パタヌンタむプを䜿甚するず、どこでもasを䜿甚する理由が少なくなり、ラむブラリの䜜成者ずダりンストリヌムの利甚者の䞡方が倉曎を簡単に壊すこずができたす。

ちょっず長蛇の列ですが、私のポむントのいく぀かがうたくいったこずを願っおいたす。


たた、私はコンパむル時のテストをたくさん曞いいたすそしお、TSチヌムもそうしおいるこずを知っおいたす。

コンパむル時のテストで、特定のstringリテラルが正芏衚珟チェックに倱敗/合栌するこずをテストできれば䟿利です。 珟時点では、これらのコンパむル時テストを行うこずはできず、代わりにランタむムテストを䜿甚する必芁がありたす。

たた、コンパむル時のテストに倱敗/合栌した堎合、ダりンストリヌムのコンシュヌマヌはこれらの文字列リテラルたたは同様のリテラルを䜿甚しお、正しい動䜜を期埅できるず確信しおいたす。


これはすぐに私たちをバベルの塔の状況ぞの道に連れお行ったようです...

これは、実際には、名目/構造タグタむプを䜿甚する堎合にさらに圓おはたりたす。 䞊蚘の䟋が瀺しおいるように、それらはラむブラリ間/バヌゞョン間の互換性のためにひどく機胜したす...

ただし、正芏衚珟/文字列パタヌンタむプは、その問題に陥らない可胜性が十分にありたす暙準化ず、


線集

スレッドでよくあるこずは、これらの正芏衚珟がテストコヌドの怜蚌に圹立぀こずです。これは、本番シナリオでは、コヌドがハヌドコヌドされたリテラルではなくランタむム提䟛の文字列に察しお実行される堎合でも、テスト文字列が「正しい"。 ただし、どちらの方法でも怜蚌関数を蚘述しおいるため、これは名目/タグ付き/ブランド文字列の匕数のように芋えたす。テストの利点は、それらが培底的に実行されるこずを知っおいるこずですしたがっお、テスト入力の゚ラヌは開発サむクルの早い段階でフラグを立おたす。

ああ...これを曞く前にたずすべおを読むべきだった...

ずにかく、文字列パタヌンタむプが圹立぀いく぀かの䟋がありたす。


HTTPルヌト宣蚀ラむブラリ

このラむブラリを䜿甚するず、HTTPルヌト宣蚀オブゞェクトを䜜成できたす。 この宣蚀は、クラむアントずサヌバヌの䞡方で䜿甚されたす。

/*snip*/
createTestCard : f.route()
    .append("/platform")
    .appendParam(s.platform.platformId, /\d+/)
    .append("/stripe")
    .append("/test-card")
/*snip*/

これらは.append()の制玄です。

  • 文字列リテラルのみ珟時点ではこれを匷制するこずはできたせんが、非リテラルを䜿甚するず、ルヌト宣蚀ビルダヌがガベヌゞになりたす
  • スラッシュを先頭から始める必芁がありたす / 
  • 末尟のスラッシュで終了しおはなりたせん / 
  • conlon文字 : を含めるこずはできたせん。 パラメヌタ甚に予玄されおいたす
  • 2぀以䞊のスラッシュを連続しお含めるこずはできたせん // 

珟圚、゚ラヌをスロヌするこれらの実行時チェックしかありたせん。 ダりンストリヌムのコンシュヌマヌは、Github READMEやJSDocコメントを読たなくおも、これらの制玄に埓う必芁がありたす。 パスを曞くだけで、赀い波線が芋えたす。


他のもの

16進文字列、英数字文字列の正芏衚珟もありたす。

私もこれを持っおいたす、

const floatingPointRegex = /^([-+])?([0-9]*\.?[0-9]+)([eE]([-+])?([0-9]+))?$/;

私はこれを芋る、

æ•Žæ•°-「3e5」を誀っお拒吊したす

これもありたす。これは敎数の正芏衚珟ではありたせんが、 floatingPointRegex 。

function parseFloatingPointString (str : string) {
    const m = floatingPointRegex.exec(str);
    if (m == undefined) {
        return undefined;
    }
    const rawCoefficientSign : string|undefined = m[1];
    const rawCoefficientValue : string = m[2];
    const rawExponentSign : string|undefined = m[4];
    const rawExponentValue : string|undefined = m[5];

    const decimalPlaceIndex = rawCoefficientValue.indexOf(".");
    const fractionalLength = (decimalPlaceIndex < 0) ?
        0 :
        rawCoefficientValue.length - decimalPlaceIndex - 1;

    const exponentValue = (rawExponentValue == undefined) ?
        0 :
        parseInt(rawExponentValue) * ((rawExponentSign === "-") ? -1 : 1);

    const normalizedFractionalLength = (fractionalLength - exponentValue);
    const isInteger = (normalizedFractionalLength <= 0) ?
        true :
        /^0+$/.test(rawCoefficientValue.substring(
            rawCoefficientValue.length-normalizedFractionalLength,
            rawCoefficientValue.length
        ));
    const isNeg = (rawCoefficientSign === "-");

    return {
        isInteger,
        isNeg,
    };
}

私もこのコメントがありたすが、

/**
    Just because a string is in integer format does not mean
    it is a finite number.

    ```ts
    const nines_80 = "99999999999999999999999999999999999999999999999999999999999999999999999999999999";
    const nines_320 = nines_80.repeat(4);
    //This will pass, 320 nines in a row is a valid integer format
    integerFormatString()("", nines_320);
    //Infinity
    parseFloat(nines_320);
    ```
*/

RegExpコンストラクタ

おかしなこずに、 RegExpコンストラクタヌは、正芏衚珟で怜蚌された文字列型の恩恵を受けたす。

今、そうです、

new(pattern: string, flags?: string): RegExp

しかし、私たちは持぀こずができたした、

new(pattern: string, flags?: PatternOf</^[gimsuy]*$/>): RegExp

TL; DR読んでください、しかし、私はこれに倚倧な努力を払いたしたcry :)

  • 文字列パタヌンタむプは、名目/構造タグタむプよりも人間工孊的です

    • ボむラヌプレヌトが少ない

  • 文字列パタヌンタむプは、名目/構造タグタむプよりもバベルの塔の状況になる可胜性が䜎くなりたす

    • 特に正芏衚珟サブタむプチェックの堎合

  • 文字列パタヌンタむプは、 stringタむプの倧きな有限/無限サブセットを定矩する最も自然な方法です。

    • この機胜を導入するず、ラむブラリの有効な文字列圢匏に぀いおより綿密に考えるようになる可胜性がありたす。

  • 文字列パタヌンタむプを䜿甚するず、䞀郚のラむブラリのコンパむル時の安党性が向䞊したす普及率に぀いおお返ししたす...逃げたす

    • RegExpコンストラクタヌ、16進数/英数字の文字列、ルヌトパス宣蚀、デヌタベヌスの文字列識別子など。


なぜあなたの正芏衚珟はずおも悪いのですか

他の人が提起した倚くのナヌスケヌスは、既存のラむブラリに合うように文字列パタヌンタむプを導入したいず考えおいたした。 そしおそれはTSチヌムを説埗しおいるようには芋えたせん。

倚くの堎合、これらの既存のラむブラリは、入力を怜蚌するために正芏衚珟をあたり䜿甚しおいないように感じたす。 たたは、正芏衚珟を䜿甚しお簡単な怜蚌を実行したす。 次に、より耇雑なパヌサヌを䜿甚しお実際の怜蚌を実行したす。

しかし、これは文字列パタヌンタむプの実際の有効なナヌスケヌスです


有効な文字列倀のスヌパヌセットを怜蚌するための文字列パタヌンタむプ

確かに、で始たるこず、文字列/ 、で終わっおいない/ 、連続しお含たれおいたせん/ 、そしお含たれおいたせん: "を枡したすHTTPパス正芏衚珟」。 ただし、これは、この正芏衚珟を枡す倀のセットが有効なHTTPパスの

さらに䞋には、 ?が䜿甚されおいない、 #が䜿甚されおいない、䞀郚の文字が゚スケヌプされおいるなどをチェックする実際のURLパスパヌサヌがありたす。

しかし、この単玔な文字列パタヌンタむプを䜿甚するず、ラむブラリのナヌザヌが遭遇する可胜性のある䞀般的な問題の倧芏暡なクラスがすでに排陀されおいたす。 たた、コンパむル時にも削陀したした。

?がク゚リ文字列の始たりであるこずを知っおいる経隓が豊富なため、ナヌザヌがHTTPパスで?を䜿甚するこずはめったにありたせん。


私はあなたがこのナヌスケヌスをすでに知っお

このスレッドは、さたざたなナヌスケヌスを意味したす。 具䜓的な䟋はもっずたれです。 厄介なこずに、これらの䟋の倚くは完党ではないようです。有効な入力を拒吊する正芏衚珟を䜿甚しおいたす。

したがっお、確かに、提案された正芏衚珟の倚くは「完党」ではありたせん。
しかし、圌らが有効な入力を拒吊しない限り、それは倧䞈倫ですよね

無効な入力を蚱可しおも倧䞈倫ですよね
実行時に「実際の」パヌサヌで完党な怜蚌を凊理できるためです。
たた、コンパむル時のチェックにより、ダりンストリヌムナヌザヌに共通する倚くの問題を排陀し、生産性を向䞊させるこずができたす。

有効な入力を拒吊する䟋は、有効な入力を拒吊せずに無効な入力を蚱可するように、簡単に倉曎できる必芁がありたす。


文字列パタヌンのタむプず共通郚分

ずにかく、文字列パタヌンタむプの亀差タむプは非垞に䟿利です

私の.append()䟋は、次のように曞くこずができたす。

append (str : (
  //Must start with forward slash
  & PatternOf</^\//>
  //Must not end with forward slash
  & PatternOf</[^/]$/>
  //Must not have consecutive forward slashes anywhere
  & not PatternOf</\/\//>
  //Must not contain colon
  & PatternOf</^[^:]+$/>
)) : SomeReturnType;

not PatternOf</\/\//>は、次のようにもなりたす。
PatternOf</^((([/])(?!\3))|[^/])+$/>しかし、これははるかに耇雑です

広範なデモンストレヌションをありがずう、 @ AnyhowStep 。 たくさん読んでくれたこずを批刀したかったのですが、ずおも参考になりたした

文字列パラメヌタヌでいっぱいの内郚APIを入力するのに苊劎するこずがよくあり、必然的に実行時にスロヌされる倚くの条件が発生したす。 必然的に、私の消費者はこれらのパタヌンチェックを耇補する必芁がありたす。圌らは䟋倖を望たないので、倱敗を凊理するための特別な方法を望んでいたす。

// Today
function createServer(id: string, comment: string) {
  if (id.match(/^[a-z]+-[0-9]+$/)) throw new Error("Server id does not match the format");
  // work
}

// Nicer
function createServer(id: PatternOf</^[a-z]+-[0-9]+$/>, comment: string) {
  // work immediately
}

文字列ずパタヌンの䞖界では、䞀般的なstringはunknownずほずんど同じであり、ランタむムチェックを優先しお倚くの型安党性を排陀し、消費する開発者に䞍䟿をもたらしたす。

蚀及されたいく぀かのナヌスケヌスでは、正芏衚珟の小さなサブセットのみが必芁になりたす。たずえば、プレフィックスの䞀臎です。

これは、可倉個匕数の皮類5453や文字列リテラル型を拡散する際の型掚論などのより䞀般的なTS蚀語機胜を䜿甚しお実行できる可胜性がありたす。

将来の憶枬

const x: ['a', 'b', 'c'] = [...'abc'] as const;

type T = [...'def']; // ['d', 'e', 'f'];
type Guard<T extends string> =
  [...T] extends [...'https://', ...any[]] ? Promise<any> : never;

declare function secureGET<
  T extends string
>(url: T): Guard<T>;

const x = secureGET('https://a.com');
x.then(...) // okay

const z = secureGET('http://z.com');
z.then(...); // error
type NaturalNumberString<T extends string> =
  [...T] extends ('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9')[] ? T : never;

蚀及されたいく぀かのナヌスケヌスでは、正芏衚珟の小さなサブセットのみが必芁になりたす。たずえば、プレフィックスの䞀臎です。

私はただ私の提案を支持し星のない蚀語の非垞に小さなスヌパヌセットであり、サブセット化ず同等性を合理的に効率的にチェックできたす。 そしおこれたでのずころ、TSチヌムが抱える最倧の懞念である、任意の正芏衚珟のパフォヌマンスの偎面に察凊する他の提案は芋たこずがありたせん。

スタヌフリヌ蚀語の問題は、その名前が瀺すように、スタヌを䜿甚できないこずです。これにより、URLなどの怜蚌が困難になりたす。 その䞊、ほずんどの人はおそらく星を欲しがり、それらを゚ミュレヌトするために任意の数の繰り返しシヌケンスを䜿甚するだけであり、サブセットをチェックするのが難しくなりたす。

そしお、ほずんどの通垞のDFA衚珟可胜な正芏衚珟のパフォヌマンスはそれほど悪くはなく、サブ/スヌパヌセットに぀いおこれらをチェックするこずが可胜です。

ただし、 *を取埗するこずはできたす。

const str : PatternOf</ab+c/> | PatternOf</ac/>

@TijmenW私の提案をもう少し詳しく読んでください-そこにはいく぀かの隠された理論的根拠ず、それを実際に実甚的にするいく぀かの小さな機胜がありたす。 星のない文法を指定するこずに盎接限定されるのではなく、小さなスヌパヌセットが拡匵されお、私のセミアドバンスのナヌスケヌスに実甚的に圹立぀ようになりたした。 特に、あなたが行うこずができたすstarof ('a' | 'b' | ...)個々の文字のために、あなたが䜿甚するこずができたすstringず同等ずしおstarof UnionOfAllCodePoints 理論的には、それはもはや原始䜜っおいない効果で。

たた、正芏蚀語が他の正芏蚀語が䞀臎するもののサブセットず䞀臎するかどうかをチェックするこずはNP完党であり、䞀般的なサブグラフ同型問題ず同等です。 これが、暙準の正芏蚀語だけを実行できない理由であり、理論的な蚈算の耇雑さを抑えるために、 starofを可胜な限り制限しようずした理由です。

TODORegExpタむプの恩恵を受ける可胜性のある実際のラむブラリ関数ず、䜿甚する実際の匏を特定しおください。

これはたったく新しいラむブラリなので、䞀粒の塩でこれを取りたすが、 https//github.com/ostrowr/ts-json-validatorのようなラむブラリは、正芏衚珟タむプのようなものではるかに䟿利になりたす。

ラむブラリの目的は、TypescriptタむプずJSONスキヌマのペア<T, s>ように生成するこずです。

  1. sが怜蚌できるすべおのタむプは、 T割り圓おるこずができたす。
  2. sに察しお実行するず、 T割り圓お可胜なタむプができるだけ少なくなり、怜蚌に倱敗したす。

正芏衚珟タむプは、怜蚌されたタむプが少なくずも次のキヌワヌドに぀いおより厳密になるこずを蚱可するこずにより、2の厳密さを改善したす。

  • format
  • patternProperties
  • propertyNames

TODORegExpタむプの恩恵を受ける可胜性のある実際のラむブラリ関数ず、䜿甚する実際の匏を特定しおください。

すべおのExcelむンタヌフェむスラむブラリは、型の怜蚌をA1たたはA5:B7ずしお䜿甚できたす。

プロパティキヌ/正芏衚珟文字列むンデクサヌ

䞀郚のラむブラリは、プロパティ名に埓っおオブゞェクトを凊理したす。 たずえば、Reactでは、名前がaria-始たるすべおのプロップにタむプを適甚したす。

interface IntrinsicElements {
    // ....
    [attributeName: /aria-\w+/]: number | string | boolean;
}

これは事実䞊盎亀抂念ですRegexプロパティキヌを远加せずにRegexタむプを远加でき、その逆も可胜です。

私はこれがここで起こっおいるすべおに少し盎亀しおいるこずを知っおいたすが、りェズリヌはあなたが私たちの入力を䜿うこずができるず思いたした。 これは、さたざたな理由でファブリックで発生し続けたす。 コンポヌネントラむブラリずしお、 data- aria-属性ず消費者ぞの

䜕かお手䌝いできるこずがありたしたらお知らせください。 😄

TSプレむグラりンド

import * as React from 'react';

// Want to reflect the same aria- and data- attributes here that JSX compiler allows in this interface:
interface TestComponentProps {
    someProp?: number;
}

const TestComponent: React.FunctionComponent<TestComponentProps> = () => {
    return null;
}

const ConsumerComponent: React.FunctionComponent = () => {
    // The React component interface allows for 'data-' and 'aria-' attributes, but we don't have any typesafe way of
    // elevating that interface or instantiating props objects that allow the same attributes. We just want to be able to 
    // define component interfaces that match what the React component interface allows without opening it up to 'any' and 
    // giving up all type safety on that interface.
    const testComponentProps: TestComponentProps = {
        someProp: 42,
        'data-attribute-allowed': 'test'
    };

    return (
        <TestComponent
            someProp={42}
            // 'data-' and 'aria-' attributes are only allowed here:
            data-attribute-allowed={'data-value'}
            aria-attribute-allowed={'aria-value'}
            {...testComponentProps}
        />
    )
}

TODORegExpタむプの恩恵を受ける可胜性のある実際のラむブラリ関数ず、䜿甚する実際の匏を特定しおください。

cronゞョブ。 これが蚀及されおいないこずに非垞に驚いた

^((\*|\d+((\/|\-|,){0,1}(\d+))*)\s*){6}$

ここに2セントを投入するだけです。HTMLのid属性ずしお䜿甚される小道具を怜蚌したいReactプロゞェクトに取り組んでいたす。 これは、次のルヌルを満たす必芁があるこずを意味したす。満たさない堎合、予期しない動䜜が発生したす。

  1. 少なくずも1人のキャラクタヌがいる
  2. スペヌスがありたせん

蚀い換えるず

interface Props {
  id: PatternOf</[^ ]+/>;
}

別の䟋 '<namespace>/<name>[@<version>]'圢匏で文字列が期埅されるsanctuary-type-identifiers

ナヌスケヌス Navigator.registerProtocolHandler()ような文字列型のDOMAPI。

MDNの匕甚

セキュリティ䞊の理由から、 registerProtocolHandler()は登録できるスキヌムを制限したす。

カスタムスキヌムは、次の条件を満たしおいる限り登録できたす。

  • カスタムスキヌムの名前はweb+始たりたす
  • カスタムスキヌムの名前には、 web+プレフィックスの埌に少なくずも1文字が含たれたす
  • カスタムスキヌムの名前には小文字のASCII文字しか含たれおいたせん。

぀たり、 Navigator.registerProtocolHandler()は、既知のstringたたはカスタムstringいずれかを想定しおいたすが、特定のスキヌマに準拠しおいる堎合に限りたす。

CSSTypeのCSSカスタムプロパティは、 --で始たるプロパティを陀くすべおのプロパティにクロヌズドタむプを提䟛する別のナヌスケヌスです。

interface Properties {
    // ....
    [customProperty: /--[a-z][^\s]*/]: number | string;
}`

関連https://github.com/frenic/csstype/issues/63

これが改良タむプず同じかどうか誰かに教えおもらえたすか https://github.com/microsoft/TypeScript/issues/7599

@ gautam1168理論的には単なるサブセットであり、文字列型を具䜓的に

蚀及されたいく぀かのナヌスケヌスでは、正芏衚珟の小さなサブセットのみが必芁になりたす。たずえば、プレフィックスの䞀臎です。

私はただ私の提案を支持し星のない蚀語の非垞に小さなスヌパヌセットであり、サブセット化ず同等性を合理的に効率的にチェックできたす。 そしおこれたでのずころ、TSチヌムが抱える最倧の懞念である、任意の正芏衚珟のパフォヌマンスの偎面に察凊する他の提案は芋たこずがありたせん。

このコメントでは、
https://github.com/microsoft/TypeScript/issues/6579#issuecomment -243338433

リンクしおいる人、
https://bora.uib.no/handle/1956/3956

タむトルは「正芏衚珟の包含問題」


しかし、

  • 右蟺の匏が1-明確である堎合、アルゎリズムは正しい答えを出したす。
  • そうでなければ、それは正しい答えを䞎えるか、答えを䞎えないかもしれたせん。

https://www.sciencedirect.com/science/article/pii/S0022000011001486

もちろん、JSの正芏衚珟は非正芏衚珟です

@AnyhowStepそれはstarof制限を解陀し、それに応じおその制限を倉曎したす。 数孊は少し抜象的であり、それは、それが具䜓的にこれらの型を䜿甚しおいない、誰もが、正匏な蚀語に粟通しおいる、実際に適甚されるかは䞍明だので、私は、制限を特城付けるより良い方法をしたいず

たた、それずは別に、そのようなものをモデル化するための挔算子ずしお、 starofより良い代替手段を匷く望んでいたす。

興味がありたす正芏衚珟の包含/包含を決定するこずは可胜ですか りィキペディアに
これはこの機胜に圱響したす絞り蟌み

if (Gmail.test(candidate)) {
    // candidate is also an Email
}

@nikeee決定可胜では、これを珟実的にするのに十分ではありたせん。 二次時間でさえ、このスケヌルでは䞀般に遅すぎたす。 TSではありたせんが、私は同様の問題に぀いおいく぀かの背景を持っおいたす。

埌方参照に盎面しお、私はそれがただ決定可胜であるず思うが、悪くはないにしおも指数関数的である可胜性が高い。 しかし、ただの知識に基づいた掚枬です。

これを明確にしおくれおありがずう

二次時間でさえ、このスケヌルでは䞀般に遅すぎたす。

だから私はそれが蚈算䞊実行可胜かどうかも尋ねたので、そうではないず思いたす。

同じこずが平等にも圓おはたる堎合、それはこの機胜のほずんどすべおのプロパティが実行䞍可胜であるこずを意味したせんか 私が間違っおいる堎合は蚂正しおください。ただし、残っおいるのはメンバヌシップだけのようです。 これだけでは圹に立たないず思いたす。

@nikeeeこのパタヌンは、比范されるすべおのタむプの文字通りすべおのプロパティに察しおチェックされるこずを芚えおおく䟡倀がありたす。 たた、正芏衚珟プロパティを持぀型の堎合、正芏衚珟が別の正芏衚珟が䞀臎するもののサブセットず䞀臎するかどうかを蚈算する必芁がありたす。これは、それ自䜓がかなり耇雑な獣です。

それは䞍可胜ではなく、ただ難しいだけです。それを実珟可胜にしたいのであれば、制限する必芁がありたす。 1぀には、JS正芏衚珟は機胜したせん。十分に拡匵可胜であるだけでなく、柔軟性もありたす。

線集私はこれを繰り返したいず思いたす明確にするために、私はTSチヌムに所属しおいたせん。 私はCSアルゎリズムの蚭蚈にたずもなバックグラりンドを持っおいたす。

うヌん、倚分あなたは「通垞の」正芏衚珟の「限定された」サブセットしかサポヌトできないでしょう。 ナヌスケヌスを考えるず、これたでのずころ正芏衚珟は非垞に単玔でした 色、電話番号など

サブセットのみをサポヌトするUXをどのように蚭蚈できたすか RegExの機胜Xが機胜するこずはナヌザヌにはあたり明確ではないかもしれたせんが、Yは機胜したせん。

ええず それを「正芏衚珟」ず呌ばないでください–初心者のために。 たぶん「パタヌンマッチング」かそこらsee_no_evil :。 しかし、ええ、おそらく簡単な䜜業ではありたせん 

このような非正芏衚珟の構文はどうですか

type TLD = 'com' | 'net' | 'org';
type Domain = `${string}.${TLD}`;
type URL = `${'http'|'https'}://${Domain}`;

const good: URL = 'https://google.com'; // ✔
const bad: URL = 'ftp://example.com'; // ✖ TypeError: 'ftp' is not assignable to type 'http' | 'https'

私の考えでは、これは型システムに非垞にうたく適合したす。 オプションの䞀臎などに異なる構文を远加できたす。

type SubDomain = `${string}.`;
type Domain = `${SubDomain}?${string}.${TLD}`;

数量詞、貪欲な挔算子のサポヌトを远加するず、非垞に堅牢なものが埗られたす。開発者がこれを䜿甚する可胜性のあるほずんどのナヌスケヌスには、おそらくそれで十分だず思いたす。

このアプロヌチの方がナヌザヌフレンドリヌだず思いたす。 ただし、型の算術挔算ず同等のようです。
https://github.com/microsoft/TypeScript/issues/15645#issuecomment-299917814およびhttps://github.com/microsoft/TypeScript/issues/15794#issuecomment-301170109によるず、これを行わないこずは蚭蚈䞊の決定です。タむプの算術。
私が誀解しおいなければ、このアプロヌチは簡単に巚倧なタむプを䜜成するこずができたす。 怜蚎

type TLD = 'com' | 'net' | 'org' | 'ly' | 'a' | 'b' | 'c' | 'd';
type Foo = `${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}`;
type Bar = `${Foo}${Foo}${Foo}${Foo}${Foo}`

これは、実装が共甚䜓型を䜿甚するこずを前提ずしおいたす。別の/より耇雑な実装で機胜する可胜性がありたす

Dislaimer私はTSチヌムの䞀員ではなく、TSに取り組んでいたせん。 ちょうど私の2c。

@rozzzly @nikeeeそれは倚かれ少なかれ私の提案の本質ですが、いく぀かの小さな機胜が欠けおいたす。 私は正芏衚珟正匏な蚀語の抂念の倧芏暡なサブセットに基づいおおり、正芏衚珟などの意味での正芏衚珟ではないため、正芏衚珟よりもはるかに匷力ではありたせんが、仕事を遂行するのに十分匷力です。

このアプロヌチの方がナヌザヌフレンドリヌだず思いたす。 ただし、型の算術挔算ず同等のようです。

数孊によれば、ある型が別の型のサブ型であるかどうかを怜蚌するこずは、文字列が特定の圢匏蚀語に含たれおいるかどうかをチェックするこずず蚈算䞊同等です。

特にドメむン怜蚌は、TLD /パブリックサフィックスの有効性もチェックする堎合、実際にはかなり耇雑なこずです。 RFCによるゞェネリックドメむン自䜓は、 /[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)+/ +最倧255文字ず同じくらい単玔ですが、䞊蚘の正芏衚珟が瀺すように完党な正芏文法を䜿甚しない限り、これでも入力が非垞に耇雑です。 @rozzzlyたたは私の提案からの文字列のみを䜿甚しお、プログラムで非垞に簡単に型を生成できたす読者の挔習ずしお残しおおきたすが、最終結果はただかなり耇雑です。

@isiahmeadows

それは倚かれ少なかれ私の提案の本質ですが、いく぀かの小さな機胜が欠けおいたす。

このスレッド党䜓を最埌に読んだのは1幎以䞊前のこずです。 私は䌑憩䞭に通知を芋たした。 @ rugkのコメントを読んでください。本質的に同じ_/非垞に類䌌した_アむデアに぀いお、かなり詳现な提案を提案したした。

...䞊蚘の正芏衚珟が瀺すように、完党な正芏文法を䜿甚しない限り、これでも入力が非垞に耇雑になりたす。 @rozzzlyたたは私の提案からの文字列のみを䜿甚しお、プログラムで非垞に簡単に型を生成できたす読者の挔習ずしお残しおおきたすが、最終結果はただかなり耇雑です。

私の考えでは、蚱可するこずを提案したような限定されたパタヌンマッチングのためのいく぀かの機胜は、非垞に単玔で、_必ずしも厳密ではない_タむピングに非垞に圹立ちたす。 私が挙げた䟋は正確にはほど遠いものであり、コンパむラヌを爆砎するこずはありたせん。

しかし、 @ nikeeeずあなたの䞡方が指摘しおいるように、これは危険な極端な状況に@types/some-popular-projectぞの曎新を公開するすべおの日を台無しにしようずしおいたす。

type MixedCaseAlphaNumeric = (
    | 'a'
    | 'b'
    | 'c'
    // and so on
);

type StrWithLengthBeteen1And64<Charset extends string> = (
    | `${Charset}`
    | `${Charset}|${Charset}`
    | `${Charset}|${Charset}|${Charset}`
    // and so on
);

function updatePassword(userID: number, password: StrWithLengthBetween1And64<MixedCaseAlphaNumeric>): void {
    // ...
}

それを芖野に入れるず、その組合は芳枬可胜な宇宙の原子以䞊の異なるタむプ。

今、私はいく぀かの非垞に長い割り圓お可胜性゚ラヌを芋おきたしたが、そのための切り捚おられおいない゚ラヌを想像しおください....

Type '"😢"' is not assignable to type '"a"|"b"|"c"..........."'.ts(2322)'

そうそう..そこにいく぀かの問題がありたす

@rozzzlyそのタむプがTupleWithLengthBeteen1And64<Charset>ず実珟可胜性の点で異なる理由は䜕ですか
コンパむラヌは、すべおのタむプを正芏化された圢匏に展開するように匷制されるわけではありたせん。展開するず、かなり通垞のタむプですぐに爆発したす。
「3から1024の間の敎数」メッセヌゞバッファの割り圓おの長さを考えおくださいでさえ範囲倖ず芋なされる堎合、珟時点ではこの問題はタむプスクリプトで意味があるずは蚀えたせん。

@simonbuchan他に䜕もないずしおも、少なくずもプレフィックスずサフィックスのタむプが存圚する必芁がありたす。 それ自䜓が倚くのDOMラむブラリずフレヌムワヌクに必芁です。

私はこれが殎打されお死にたした、そしおいく぀かの良い提案がすでに䞎えられたこずを知っおいたす。 しかし、私は、䞀郚の人が少し面癜いず思うかもしれないものを远加したかっただけです。

埌方参照に盎面しお、私はそれがただ決定可胜であるず思うが、悪くはないにしおも指数関数的である可胜性が高い。 しかし、ただの知識に基づいた掚枬です。

逆参照により、正芏衚珟は文脈自由文法のスヌパヌセットである文脈䟝存文法を蚘述できたす。 そしお、CFGの蚀語の平等は決定䞍可胜です。 したがっお、線圢拘束オヌトマトンず同等のCSGの堎合はさらに悪化したす。


DFAに倉換できるすべおの正芏衚珟が正芏衚珟連結、和集合、星、共通郚分、補集合などで䜿甚されおいるずするず、正芏衚珟をNFAに倉換するずOnになり、2の積が埗られたす。 NFAはOm * nであり、受け入れ状態の結果のグラフをトラバヌスするずOm * nになりたす。 したがっお、2぀の正芏衚珟の蚀語の同等性/サブセットをチェックするこずもOm * nです。

問題は、ここではアルファベットが本圓に倧きいこずです。 教科曞は、DFA / NFA /正芏衚珟に぀いお話すずき、通垞、サむズ1〜5のアルファベットに制限されおいたす。 しかし、JS正芏衚珟を䜿甚するず、アルファベットずしおすべおのUnicodeを䜿甚できたす。 確かに、スパヌス配列やその他の巧劙なハックず等匏/サブセットテストの最適化を䜿甚しお遷移関数を衚す効率的な方法がありたす...

定期的な割り圓おの型チェックをある皋床効率的に行うこずができるず確信しおいたす。

次に、すべおの非正芏割り圓おで、明瀺的な型アサヌションが必芁になる堎合がありたす。

私は最近、小さな有限オヌトマトンプロゞェクトに取り組んだので、情報はただ私の心の䞭で新鮮です= x

私が誀解しおいなければ、このアプロヌチは簡単に巚倧なタむプを䜜成するこずができたす。 怜蚎

type TLD = 'com' | 'net' | 'org' | 'ly' | 'a' | 'b' | 'c' | 'd';
type Foo = `${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}${TLD}`;
type Bar = `${Foo}${Foo}${Foo}${Foo}${Foo}`

これは、実装が共甚䜓型を䜿甚するこずを前提ずしおいたす。別の/より耇雑な実装で機胜する可胜性がありたす

おかしなこずに、これはたさに新しいテンプレヌト文字列リテラルタむプで可胜なこずです。 このケヌスは、共甚䜓タむプのしきい倀を蚭定するこずで回避できるようです。

@AnyhowStep JS

線集粟床

@rozzzlyからのこのコメントがTS4.1.0で毎晩動䜜するこずを確認したした

type TLD = 'com' | 'net' | 'org';
type Domain = `${string}.${TLD}`;
type Url = `${'http'|'https'}://${Domain}`;

const success: Url = 'https://example.com';
const fail: Url = 'example.com';
const domain: Domain = 'example.com';

遊び堎で詊しおみお、 failにコンパむル時゚ラヌがあるこずを確認しおください🀩


曎新この機胜を少し詊した埌は、倚くのナヌスケヌスをカバヌしたせん。 たずえば、16進カラヌ文字列では機胜したせん。

type HexChar = '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
type HexColor = `#${HexChar}${HexChar}${HexChar}${HexChar}${HexChar}${HexChar}`;
let color: HexColor = '#123456';

今日では、 「匏は耇雑すぎお衚珟できない共甚䜓型を生成したす。2590」で倱敗したす

@rozzzlyからのこのコメントがTS4.1.0で毎晩動䜜するこずを確認したした

type TLD = 'com' | 'net' | 'org';
type Domain = `${string}.${TLD}`;
type Url = `${'http'|'https'}://${Domain}`;

const success: Url = 'https://example.com';
const fail: Url = 'example.com';
const domain: Domain = 'example.com';

遊び堎で詊しおみお、 failにコンパむル時゚ラヌがあるこずを確認しおください🀩

これは、むンデックスに適甚できれば、UXラむブラリで私たちのほずんどが盎面するデヌタたたはアリアの問題を解決したす。

基本的にこれですが、TSでは文字列しか蚱可されおいないため、明らかに機胜したせん。 番号。 これは本質的に文字列なので、有効にできたすか
https://www.typescriptlang.org/play?target=99&ts=4.1.0-dev.20201001#code/LAKALgngDgpgBAEQIZicgzgCzgXjgAwBIBvAcgBMUkBaUgXxPTACcBLAOwHM78BuUDmBjMAZkgDG8AJIAVGEzjFQcFXADalVBkwAFZgHsoALmRakWALpGmbLvxB1QocfvYL0AV3GT06I3Fl5MFxFCipqISZSI1JIsHpeIA

_Update_この機胜を少し詊した埌は、倚くのナヌスケヌスをカバヌしたせん。 たずえば、16進カラヌ文字列では機胜したせん。

type HexChar = '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
type HexColor = `#${HexChar}${HexChar}${HexChar}${HexChar}${HexChar}${HexChar}`;
let color: HexColor = '#123456';

今日では、 「匏は耇雑すぎお衚珟できない共甚䜓型を生成したす。2590」で倱敗したす

リリヌスノヌトには、この制限ぞの蚀及がいく぀かありたした。 可胜なすべおの有効な組み合わせのリストを䜜成したす。この堎合、16,777,216぀たり、16 ^ 6のメンバヌで結合を䜜成したす。

これは玠晎らしいアむデアです... Igmatは、2016幎に、ずにかく玙の䞊で芋栄えのする玠晎らしい投皿をいく぀か䜜成したした。

関数に枡されたオブゞェクトリテラルのキヌが有効なcssクラス名であるこずを確認したかったので、これを芋぀けたした。 実行時に簡単に確認できたす...しかし、特にオブゞェクトリテラルをハヌドコヌディングしおいるだけで、typescriptが次のこずを理解する必芁がない状況では、typescriptがコンパむル時にこれを実行できるこずは明らかです。 MyUnionExtendedExoticタむプはSomeArbitraryRegexTypeを満たしたす。

倚分い぀か私はより生産的な貢献をするのに十分な知識があるでしょう/

@rozzzlyからのこのコメントがTS4.1.0で毎晩動䜜するこずを確認したした

わお。 私は正盎なずころ、少なくずもすぐには、これが実装されるこずを期埅しおいたせんでした。

@ chadlavi-刀䟋集

リリヌスノヌトには、この制限ぞの蚀及がいく぀かありたした。 可胜なすべおの有効な組み合わせのリストを䜜成したす。この堎合、16,777,216぀たり、16 ^ 6のメンバヌで結合を䜜成したす。

パフォヌマンスの面で問題になる前に、そのナニオンがどれだけ倧きくなるかを知りたいず思いたす。 @styfleの䟋は、その倩井にぶ぀かるのがいかに簡単かを瀺しおいたす。 明らかに、耇雑な型の有甚性ずパフォヌマンスの収穫逓枛がある皋床芋蟌たれたす。

@thehappycheese

関数に枡されたオブゞェクトリテラルのキヌが有効なcssクラス名であるこずを確認したかった

珟圚の実装では䞍可胜だず私はかなり自信を持っおいたす。 数量詞ず範囲がサポヌトされおいる堎合は、おそらくBEMスタむルのクラス名の怜蚌が行われたす。 そのための暙準のjs正芏衚珟は、ひどいものではありたせん。
^\.[a-z]([a-z0-9-]+)?(__([a-z0-9]+-?)+)?(--([a-z0-9]+-?)+){0,2}$
たた、実装が珟状でぱンドツヌ゚ンドの䞀臎であるか䜕もないため、アンカヌを砎棄するため、 ^ず$が暗瀺されたす。 これは、有効なcssセレクタヌの狭いサブセットに察する比范的単玔な正芏衚珟です。 䟋 ಠ_ಠは有効なクラス名です。 冗談じゃないよ。

ごめんなさい。 私はこれをしなければなりたせんでした。

TypeScriptで正芏蚀語を実装したした。

より正確には、TS4.1を䜿甚しお単玔な決定性有限オヌトマトンを実装したした

぀たり、TSにチュヌリングマシンをすでに実装できたす。 したがっお、DFAずPDAは、それに比べお「簡単」です。

そしお、テンプレヌト文字列はこれをより䜿いやすくしたす。


コアタむプは実際にはシンプルで、30LOC未満に収たりたす。

type Head<StrT extends string> = StrT extends `${infer HeadT}${string}` ? HeadT : never;

type Tail<StrT extends string> = StrT extends `${string}${infer TailT}` ? TailT : never;

interface Dfa {
    startState : string,
    acceptStates : string,
    transitions : Record<string, Record<string, string>>,
}

type AcceptsImpl<
    DfaT extends Dfa,
    StateT extends string,
    InputT extends string
> =
    InputT extends "" ?
    (StateT extends DfaT["acceptStates"] ? true : false) :
    AcceptsImpl<
        DfaT,
        DfaT["transitions"][StateT][Head<InputT>],
        Tail<InputT>
    >;

type Accepts<DfaT extends Dfa, InputT extends string> = AcceptsImpl<DfaT, DfaT["startState"], InputT>;

それは難しい郚分であるオヌトマトンを指定しおいたす。

しかし、誰かがTypeScriptDFA™ゞェネレヌタヌに正芏衚珟を䜜成できるず確信しおいたす...


たた、「長さ6の16進文字列」の䟋では、醜いハッカヌを䜿甚しお、関数パラメヌタヌが正芏衚珟に䞀臎する文字列のみを受け入れるようにできるこずを瀺しおいたす。

declare function takesOnlyHex<StrT extends string> (
    hexString : Accepts<HexStringLen6, StrT> extends true ? StrT : {__err : `${StrT} is not a hex-string of length 6`}
) : void;

//OK
takesOnlyHex("DEADBE")

//Error: Argument of type 'string' is not assignable to parameter of type '{ __err: "DEADBEEF is not a hex-string of length 6"; }'.
takesOnlyHex("DEADBEEF")

//OK
takesOnlyHex("01A34B")

//Error: Argument of type 'string' is not assignable to parameter of type '{ __err: "01AZ4B is not a hex-string of length 6"; }'.
takesOnlyHex("01AZ4B")

これがボヌナスプレむグラりンドです。 正芏衚珟/^hello .*/実装したす

そしお別の遊び堎; 正芏衚珟/ world$/実装したす

最埌の䟋ずしお、 Playground ; これは浮動小数点文字列の正芏衚珟です

@AnyhowStepさお、私はあなたのDFAのアむデアを䜿甚しお、単玔な正芏衚珟[abc]{4}を実装したした。これは、文字abcが欠萜しおいるが、正確に4の長さであるこずを意味したすaaaa、abcc、bbccなど。
遊び堎

https://cyberzhg.github.io/toolbox/min_dfa?regex=ZCgoYmQqYiopKmMpKg==

https://github.com/Cyber​​ZHG/toolbox

もっず意志力があれば、䞊蚘のようなものを぀かんで、正芏衚珟をTSDFA™に倉えるために䜿甚したす笑

さお、私はプロトタむプを䞀緒に投げたした、

https://glitch.com/~sassy-valiant-heath

[線集] https://glitch.com/~efficacious-valley-repair <-これにより、より耇雑な正芏衚珟の出力が倧幅に向䞊したす。

[線集] Glitchは、長期間䜿甚されおいない無料のプロゞェクトをアヌカむブするようです。 だから、ここにファむルを含むgitリポゞトリがありたす、
https://github.com/AnyhowStep/efficacious-valley-repair/tree/main/app

ステップ1、ここに正芏衚珟を入力したす。
image

ステップ2、[倉換]をクリックし、
image

ステップ3、生成されたTSプレむグラりンドURLをクリックし、
image

ステップ4、 InLanguage_0たで䞋にスクロヌルしたす。
image

ステップ5、入力倀で遊んで、
image

image

https://www.npmjs.com/package/regex2dfaの䜜者である@kpdyerに、倉換の手間のかかる䜜業を叫んでください。

誰かがもう少し匷力なものを必芁ずする堎合に備えお、ここにチュヌリングマシンがありたす😆

遊び堎

このスレッドは長すぎお読むこずができず、コメントの倚くはテンプレヌトリテラルタむプによっお察凊されおいるか、トピックから倖れおいたす。 この機胜によっお有効になる可胜性のある残りのナヌスケヌスに぀いお説明するために、新しい問題41160を䜜成したした。 ここで型システムパヌサヌに぀いお匕き続き議論しおください😀

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡