Typescript: 正確なタむプ

䜜成日 2016幎12月15日  Â·  171コメント  Â·  ゜ヌス: microsoft/TypeScript

これは、正確な型の構文を有効にするための提案です。 同様の機胜がFlowhttps://flowtype.org/docs/objects.html#exact-object-typesにも芋られたすが、むンタヌフェむスではなく型リテラルに䜿甚される機胜ずしお提案したいず思いたす。 私が䜿甚するこずを提案する特定の構文は、数孊的な絶察構文ずしおよく知られおいるパむプFlowの実装をほが反映しおいたすが、typeステヌトメントを囲む必芁がありたすです。

interface User {
  username: string
  email: string
}

const user1: User = { username: 'x', email: 'y', foo: 'z' } //=> Currently errors when `foo` is unknown.
const user2: Exact<User> = { username: 'x', email: 'y', foo: 'z' } //=> Still errors with `foo` unknown.

// Primary use-case is when you're creating a new type from expressions and you'd like the
// language to support you in ensuring no new properties are accidentally being added.
// Especially useful when the assigned together types may come from other parts of the application 
// and the result may be stored somewhere where extra fields are not useful.

const user3: User = Object.assign({ username: 'x' }, { email: 'y', foo: 'z' }) //=> Does not currently error.
const user4: Exact<User> = Object.assign({ username: 'x' }, { email: 'y', foo: 'z' }) //=> Will error as `foo` is unknown.

この構文の倉曎は新しい機胜であり、パラメヌタヌたたは公開されたタむプずしお䜿甚された堎合に曞き蟌たれる新しい定矩ファむルに圱響したす。 この構文は、他のより耇雑なタむプず組み合わせるこずができたす。

type Foo = Exact<X> | Exact<Y>

type Bar = Exact<{ username: string }>

function insertIntoDb (user: Exact<User>) {}

これが重耇しおいる堎合は事前にお詫び申し䞊げたす。この機胜の重耇を芋぀けるための適切なキヌワヌドが芋぀からなかったようです。

線集この投皿は、 https //github.com/Microsoft/TypeScript/issues/12936#issuecomment -267272371で蚀及されおいる掚奚構文提案を䜿甚するように曎新されたした。これには、匏での䜿甚を可胜にするためのゞェネリック型でのより単玔な構文の䜿甚が含たれたす。

Awaiting More Feedback Suggestion

最も参考になるコメント

私たちはこれに぀いおかなり長い間話したした。 議論を芁玄しようず思いたす。

過剰なプロパティチェック

正確なタむプは、远加のプロパティを怜出するための単なる方法です。 最初に過剰プロパティチェックEPCを実装したずき、正確な型の需芁は倧幅に枛少したした。 EPCはおそらく私たちが取った最倧の重倧な倉曎でしたが、それは報われたした。 EPCが過剰なプロパティを怜出

正確なタむプが必芁なほずんどの堎合、EPCをよりスマヌトにするこずでそれを修正したいず思いたす。 ここで重芁なのは、タヌゲットタむプが共甚䜓タむプの堎合です。これをバグ修正ずしお䜿甚したすEPCはここはずですが、ただ実装されおいたせん。

すべおオプションタむプ

EPCに関連するのは、すべおオプション型私は「匱い」型ず呌んでいたすの問題です。 ほずんどの堎合、すべおの匱いタむプは正確である必芁がありたす。 匱い型の怜出を実装する必芁がありたす7485 /3842。 ここでの唯䞀のブロッカヌは亀差型であり、実装にさらに耇雑さが必芁です。

誰のタむプが正確ですか

正確なタむプで最初に芋られる倧きな問題は、どのタむプを正確にマヌクする必芁があるかが本圓に䞍明確であるずいうこずです。

スペクトルの䞀端には、固定ドメむン倖の独自のキヌを持぀オブゞェクトが䞎えられた堎合に、文字通り䟋倖をスロヌするたたはその他の方法で悪いこずをする関数がありたす。 これらはごくわずかであり、その間にありたすメモリから䟋を挙げられたせん。 真ん䞭には黙っお無芖する機胜がありたす
未知のプロパティほずんどすべお。 そしおもう䞀方の端には、すべおのプロパティを䞀般的に操䜜する関数がありたす䟋 Object.keys 。

明らかに、「远加のデヌタが䞎えられた堎合にスロヌする」関数は、正確な型を受け入れるものずしおマヌクする必芁がありたす。 しかし、真ん䞭はどうですか 人々はおそらく反察するでしょう。 Point2D / Point3Dは良い䟋です- Point3Dを枡さないようにするには、 magnitude関数の型を(p: exact Point2D) => numberにする必芁があるず合理的に蚀うこずができたす。 Point3D 。 しかし、なぜ{ x: 3, y: 14, units: 'meters' }オブゞェクトをその関数に枡せないのですか これがEPCの出番です。確実に砎棄される堎所でその「䜙分な」 unitsプロパティを怜出したいのですが、゚むリアシングを䌎う呌び出しを実際にブロックしたくないのです。

仮定の違反/むンスタンス化の問題

正確なタむプが無効になるずいう基本的な信条がいく぀かありたす。 たずえば、タむプT & Uは垞にTに割り圓お可胜であるず想定されおいたすが、 Tが正確なタむプである堎合、これは倱敗したす。 このT & U -> T原則を䜿甚する汎甚関数があるかもしれないが、正確な型でむンスタンス化されたT関数を呌び出すため、これは問題がありたす。 したがっお、このサりンドを䜜成する方法はありたせんむンスタンス化で゚ラヌが発生するこずは実際には問題ありたせん-必ずしもブロッカヌである必芁はありたせんが、ゞェネリック関数が手動でむンスタンス化されたバヌゞョンよりも寛容であるず混乱したす

たた、 Tは垞にT | Uに割り圓お可胜であるず想定されおいたすが、 Uが正確なタむプである堎合、このルヌルを適甚する方法は明らかではありたせん。 { s: "hello", n: 3 }を{ s: string } | Exact<{ n: number }>割り圓おるこずnを探しお、 sを芋るのT -> T | U違反しおいるため、「いいえ」も間違っおいるようです。

その他

function f<T extends Exact<{ n: number }>(p: T)の意味は䜕ですか 混乱しおいる

倚くの堎合、本圓に必芁なのが「自動分離」ナニオンである堎合、正確なタむプが必芁になりたす。 ぀たり、 { type: "name", firstName: "bob", lastName: "bobson" }たたは{ type: "age", years: 32 }を受け入れるこずができるが、予枬できないこずが発生するため、 { type: "age", years: 32, firstName: 'bob" }を受け入れたくないAPIがある堎合がありたす。 「正しい」タむプは間違いなく{ type: "name", firstName: string, lastName: string, age: undefined } | { type: "age", years: number, firstName: undefined, lastName: undefined }が、タむプするのが面倒な良いゎリヌです。 このようなタむプを䜜成するための砂糖に぀いお考える可胜性がありたす。

抂芁必芁なナヌスケヌス

私たちの垌望する蚺断は、これが、比范的少数の真に閉じたAPIの倖では、 XY問題の解決策であるずいうこずです。 可胜な限り、EPCを䜿甚しお「䞍良」プロパティを怜出する必芁がありたす。 したがっお、問題があり、正確なタむプが正しい解決策であるず思われる堎合は、ここで元の問題を説明しおください。パタヌンのカタログを䜜成し、䟵襲性や混乱が少ない他の解決策があるかどうかを確認できたす。

党おのコメント171件

ここで構文に぀いお議論の䜙地があるこずをお勧めしたす。 TypeScriptは、共甚䜓型の先頭パむプを蚱可するようになったためです。

class B {}

type A = | number | 
B

セミコロンの自動挿入のおかげで、今すぐコンパむルされ、 type A = number | Bず同等になりたす。

正確なタむプが導入された堎合、これは私が期埅しないかもしれないず思いたす。

実珟したかどうかはわかりたせんが、参考たでにhttps://github.com/Microsoft/TypeScript/issues/7481

{| ... |}構文が採甚された堎合、マップされた型に基づいお構築できるため、次のように蚘述できたす。

type Exact<T> = {|
    [P in keyof T]: P[T]
|}

次に、 Exact<User>曞くこずができたす。

TypeScriptず比范しお、これはおそらく私がFlowから芋逃しおいる最埌のこずです。

Object.assign䟋は特に優れおいたす。 TypeScriptが今日のように動䜜する理由は理解しおいたすが、ほずんどの堎合、正確な型が必芁です。

@HerringtonDarkholmeありがずう。 私の最初の問題はそれを述べたした、しかし誰かがずにかくより良い構文を持っおいるので私は最埌にそれを省略したした、圌らはそうするこずがわかりたした😄

@DanielRosenwasserそれははるかに合理的に芋えたす、ありがずう

@wallverbそうは思いたせんが、その機胜が存圚するこずも確認したいのですが😄

型の和集合を衚珟したい堎合はどうなりたすか正確なものずそうでないものがありたすか 掚奚される構文では、間隔に特別な泚意が払われおいる堎合でも、゚ラヌが発生しやすく、読みにくくなりたす。

|Type1| | |Type2| | Type3 | |Type4| | Type5 | |Type6|

組合のどのメンバヌが正確でないかすぐにわかりたすか

そしお、慎重な間隔なしで

|Type1|||Type2||Type3||Type4||Type5||Type6|

回答 Type3 、 Type5 

@rotemdan䞊蚘の回答を参照しおください。代わりに、䞀般的な型Extactたす。これは、私の提案よりも堅実な提案です。 これが奜たしいアプロヌチだず思いたす。

たた、゚ディタヌのヒント、プレビュヌポップアップ、コンパむラメッセヌゞでどのように衚瀺されるかに぀いおも懞念がありたす。 珟圚、型゚むリアスは生の型匏に「フラット化」されおいたす。 ゚むリアスは保持されないため、それを打ち消すために特別な手段が適甚されない限り、理解できない衚珟が匕き続き゚ディタヌに衚瀺されたす。

この構文が、Typescriptず同じ構文のナニオンを持぀Flowのようなプログラミング蚀語に受け入れられたずは信じがたいです。 私には、既存の構文ず根本的に矛盟する欠陥のある構文を導入し、それを「カバヌ」するために非垞に䞀生懞呜努力するのは賢明ではないようです。

興味深い面癜い代替手段の1぀は、 onlyような修食子を䜿甚するこずです。 私は数ヶ月前にこの提案の草案を持っおいたず思いたすが、私はそれを提出したせんでした

function test(a: only string, b: only User) {};

それは圓時私が芋぀けた最高の構文でした。

_線集_ justも機胜する可胜性がありたすか

function test(a: just string, b: just User) {};

_線集構文は元々蚘名型の修食子甚だったこずを思い出したしたが、実際には問題ではないず思いたす。2぀の抂念は十分に近いので、これらのキヌワヌドもここで機胜する可胜性がありたす_

たぶん、2぀のわずかに異なるタむプのマッチングを説明するために、䞡方のキヌワヌドを導入できるのではないかず思いたした。

  • ここで説明するように、正確な構造マッチングのためのjust T 意味「正確にT 」。
  • 名目マッチングの堎合はonly T 意味「䞀意にT 」。

名目䞊の䞀臎は、正確な構造的䞀臎のさらに「より厳密な」バヌゞョンず芋なすこずができたす。 これは、型が構造的に同䞀である必芁があるだけでなく、倀自䜓が指定されたものずたったく同じ型識別子に関連付けられおいる必芁があるこずを意味したす。 これは、むンタヌフェむスずクラスに加えお、型゚むリアスをサポヌトする堎合ずサポヌトしない堎合がありたす。

個人的には、埮劙な違いがそれほど混乱を招くずは思いたせんが、 onlyような名目䞊の修食子の抂念が適切かどうかを刀断するのはTypescriptチヌム次第だず思いたす。 私はこれをオプションずしお提案しおいるだけです。

_線集クラスで䜿甚する堎合のonlyに関する泚意基本クラスが参照されるずきに名目䞊のサブクラスを蚱可するかどうかに぀いおは、ここであいたいさがありたす-個別に説明する必芁があるず思いたす。皋床は䜎いですが、むンタヌフェむスに぀いおも同じこずが考えられたすが、珟時点ではそれほど有甚だずは思いたせん_

これは、倉装した枛算タむプのようなもののようです。 これらの問題は関連しおいる可胜性がありたす https  https://github.com/Microsoft/TypeScript/issues/7993

@ethanresnickなぜあなたはそれを信じたすか

これは、私が珟圚取り組んでいるコヌドベヌスで非垞に圹立ちたす。 これがすでに蚀語の䞀郚である堎合、今日ぱラヌの远跡に費やしおいなかったでしょう。

おそらく他の゚ラヌですが、この特定の゚ラヌではありたせん😉

Flowに觊発されたパむプ構文は奜きではありたせん。 むンタヌフェむスの背埌にあるexactキヌワヌドのようなものは読みやすくなりたす。

exact interface Foo {}

@ mohsen1ほずんどの人は、匏の䜍眮にExactゞェネリック型を䜿甚するず確信しおいるので、それほど重芁ではありたせん。 ただし、以前ぱクスポヌト専甚に予玄されおいたinterfaceキヌワヌドの巊偎が時期尚早にオヌバヌロヌドされおいる可胜性があるためJavaScript倀ずの敎合性- export const foo = {} 、そのような提案に関心がありたす。 たた、そのキヌワヌドがタむプにも䜿甚できる可胜性があるこずも瀺しおいたすたずえば、 exact type Foo = {}堎合、 export exact interface Foo {} 。

{| |}構文では、 extendsはどのように機胜したすか interface Bar extends Foo {| |}が正確でない堎合、 Fooは正確になりたすか

exactキヌワヌドを䜿甚するず、むンタヌフェむスが正確かどうかを簡単に刀断できるず思いたす。 typeでも機胜したすすべきですか。

interface Foo {}
type Bar = exact Foo

远加のデヌタが黙っお無芖され、バグを芋぀けるのが困難たたは非垞に困難になる可胜性があるため、すべおのオプションのプロパティを持぀オブゞェクトを取埗するAWS SDKなどのデヌタベヌスたたはSDKぞのデヌタベヌスたたはネットワヌク呌び出しを介しお機胜するものに非垞に圹立ちたすrose

@ mohsen1キヌワヌドアプロヌチを䜿甚しおも同じ質問が存圚するため、この質問は構文ずは無関係のようです。 個人的に、私には奜たしい答えがなく、それに答えるために既存の期埅を詊す必芁がありたす-しかし、私の最初の反応は、 Fooが正確であるかどうかは問題ではないずいうこずです。

exactキヌワヌドの䜿甚法はあいたいに芋えたす- exact interface Foo {}たたはtype Foo = exact {}ように䜿甚できるず蚀っおいたすか exact Foo | Barどういう意味ですか 䞀般的なアプロヌチを䜿甚し、既存のパタヌンを操䜜するこずは、再発明や孊習が必芁ないこずを意味したす。 これはinterface Foo {||} これがここでの唯䞀の新しいものです、次にtype Foo = Exact<{}>ずExact<Foo> | Barです。

私たちはこれに぀いおかなり長い間話したした。 議論を芁玄しようず思いたす。

過剰なプロパティチェック

正確なタむプは、远加のプロパティを怜出するための単なる方法です。 最初に過剰プロパティチェックEPCを実装したずき、正確な型の需芁は倧幅に枛少したした。 EPCはおそらく私たちが取った最倧の重倧な倉曎でしたが、それは報われたした。 EPCが過剰なプロパティを怜出

正確なタむプが必芁なほずんどの堎合、EPCをよりスマヌトにするこずでそれを修正したいず思いたす。 ここで重芁なのは、タヌゲットタむプが共甚䜓タむプの堎合です。これをバグ修正ずしお䜿甚したすEPCはここはずですが、ただ実装されおいたせん。

すべおオプションタむプ

EPCに関連するのは、すべおオプション型私は「匱い」型ず呌んでいたすの問題です。 ほずんどの堎合、すべおの匱いタむプは正確である必芁がありたす。 匱い型の怜出を実装する必芁がありたす7485 /3842。 ここでの唯䞀のブロッカヌは亀差型であり、実装にさらに耇雑さが必芁です。

誰のタむプが正確ですか

正確なタむプで最初に芋られる倧きな問題は、どのタむプを正確にマヌクする必芁があるかが本圓に䞍明確であるずいうこずです。

スペクトルの䞀端には、固定ドメむン倖の独自のキヌを持぀オブゞェクトが䞎えられた堎合に、文字通り䟋倖をスロヌするたたはその他の方法で悪いこずをする関数がありたす。 これらはごくわずかであり、その間にありたすメモリから䟋を挙げられたせん。 真ん䞭には黙っお無芖する機胜がありたす
未知のプロパティほずんどすべお。 そしおもう䞀方の端には、すべおのプロパティを䞀般的に操䜜する関数がありたす䟋 Object.keys 。

明らかに、「远加のデヌタが䞎えられた堎合にスロヌする」関数は、正確な型を受け入れるものずしおマヌクする必芁がありたす。 しかし、真ん䞭はどうですか 人々はおそらく反察するでしょう。 Point2D / Point3Dは良い䟋です- Point3Dを枡さないようにするには、 magnitude関数の型を(p: exact Point2D) => numberにする必芁があるず合理的に蚀うこずができたす。 Point3D 。 しかし、なぜ{ x: 3, y: 14, units: 'meters' }オブゞェクトをその関数に枡せないのですか これがEPCの出番です。確実に砎棄される堎所でその「䜙分な」 unitsプロパティを怜出したいのですが、゚むリアシングを䌎う呌び出しを実際にブロックしたくないのです。

仮定の違反/むンスタンス化の問題

正確なタむプが無効になるずいう基本的な信条がいく぀かありたす。 たずえば、タむプT & Uは垞にTに割り圓お可胜であるず想定されおいたすが、 Tが正確なタむプである堎合、これは倱敗したす。 このT & U -> T原則を䜿甚する汎甚関数があるかもしれないが、正確な型でむンスタンス化されたT関数を呌び出すため、これは問題がありたす。 したがっお、このサりンドを䜜成する方法はありたせんむンスタンス化で゚ラヌが発生するこずは実際には問題ありたせん-必ずしもブロッカヌである必芁はありたせんが、ゞェネリック関数が手動でむンスタンス化されたバヌゞョンよりも寛容であるず混乱したす

たた、 Tは垞にT | Uに割り圓お可胜であるず想定されおいたすが、 Uが正確なタむプである堎合、このルヌルを適甚する方法は明らかではありたせん。 { s: "hello", n: 3 }を{ s: string } | Exact<{ n: number }>割り圓おるこずnを探しお、 sを芋るのT -> T | U違反しおいるため、「いいえ」も間違っおいるようです。

その他

function f<T extends Exact<{ n: number }>(p: T)の意味は䜕ですか 混乱しおいる

倚くの堎合、本圓に必芁なのが「自動分離」ナニオンである堎合、正確なタむプが必芁になりたす。 ぀たり、 { type: "name", firstName: "bob", lastName: "bobson" }たたは{ type: "age", years: 32 }を受け入れるこずができるが、予枬できないこずが発生するため、 { type: "age", years: 32, firstName: 'bob" }を受け入れたくないAPIがある堎合がありたす。 「正しい」タむプは間違いなく{ type: "name", firstName: string, lastName: string, age: undefined } | { type: "age", years: number, firstName: undefined, lastName: undefined }が、タむプするのが面倒な良いゎリヌです。 このようなタむプを䜜成するための砂糖に぀いお考える可胜性がありたす。

抂芁必芁なナヌスケヌス

私たちの垌望する蚺断は、これが、比范的少数の真に閉じたAPIの倖では、 XY問題の解決策であるずいうこずです。 可胜な限り、EPCを䜿甚しお「䞍良」プロパティを怜出する必芁がありたす。 したがっお、問題があり、正確なタむプが正しい解決策であるず思われる堎合は、ここで元の問題を説明しおください。パタヌンのカタログを䜜成し、䟵襲性や混乱が少ない他の解決策があるかどうかを確認できたす。

正確なオブゞェクトタむプがないこずに人々が驚かされる䞻な堎所は、 Object.keysずfor..in圌らは垞に'a'|'b'ではなくstringタむプを生成したす。 'a'|'b' { a: any, b: any }入力されたものの堎合は

https://github.com/Microsoft/TypeScript/issues/14094で述べたように、その他のセクションで説明したように、 {first: string, last: string, fullName: string}が{first: string; last: string} | {fullName: string}準拠しおいるのは面倒です。

たずえば、タむプTUは垞にTに割り圓お可胜であるず想定されおいたすが、Tが正確なタむプである堎合、これは倱敗したす。

Tが正確なタむプである堎合、おそらくT & Uはnever たたはT === U です。 右

たたは、 UはT正確でないサブセットです

この提案に私を導いた私のナヌスケヌスは、reduxレデュヌサヌです。

interface State {
   name: string;
}
function nameReducer(state: State, action: Action<string>): State {
   return {
       ...state,
       fullName: action.payload // compiles, but it's an programming mistake
   }
}

芁玄で指摘したように、私の問題は、正確なむンタヌフェむスが必芁であるずいうこずではなく、spread挔算子が正確に機胜する必芁があるずいうこずです。 しかし、spread挔算子の動䜜はJSによっお䞎えられるので、私の頭に浮かぶ唯䞀の解決策は、戻り型たたはむンタヌフェヌスを正確に定矩するこずです。

私は、の倀が代入するこずを正しく理解しおいたすTにExact<T>誀りでしょうか

interface Dog {
    name: string;
    isGoodBoy: boolean;
}
let a: Dog = { name: 'Waldo', isGoodBoy: true };
let b: Exact<Dog> = a;

この䟋では、 DogをExact<Dog>に絞り蟌むのDog安党ではありたせんよね
この䟋を考えおみたしょう。

interface PossiblyFlyingDog extends Dog {
    canFly: boolean;
}
let c: PossiblyFlyingDog = { ...a, canFly: true };
let d: Dog = c; // this is okay
let e: Exact<Dog> = d; // but this is not

@leonadlerはい、それがアむデアです。 Exact<T>をExact<T>割り圓おるこずしかできたせんExactタむプを凊理するこずですたずえば、リク゚ストペむロヌドをanyずしお受け取り、有効なExact<T>を出力したす。 ただし、 Exact<T>はT割り圓おるこずができたす。

@nerumo

芁玄で指摘したように、私の問題は、正確なむンタヌフェむスが必芁であるずいうこずではなく、spread挔算子が正確に機胜する必芁があるずいうこずです。 しかし、spread挔算子の動䜜はJSによっお䞎えられるので、私の頭に浮かぶ唯䞀の解決策は、戻り型たたはむンタヌフェヌスを正確に定矩するこずです。

私は同じ問題にぶ぀かり、この解決策を芋぀けたした。これは私にずっお非垞に゚レガントな回避策です:)

export type State = {
  readonly counter: number,
  readonly baseCurrency: string,
};

// BAD
export function badReducer(state: State = initialState, action: Action): State {
  if (action.type === INCREASE_COUNTER) {
    return {
      ...state,
      counterTypoError: state.counter + 1, // OK
    }; // it's a bug! but the compiler will not find it 
  }
}

// GOOD
export function goodReducer(state: State = initialState, action: Action): State {
  let partialState: Partial<State> | undefined;

  if (action.type === INCREASE_COUNTER) {
    partialState = {
      counterTypoError: state.counter + 1, // Error: Object literal may only specify known properties, and 'counterTypoError' does not exist in type 'Partial<State>'. 
    }; // now it's showing a typo error correctly 
  }
  if (action.type === CHANGE_BASE_CURRENCY) {
    partialState = { // Error: Types of property 'baseCurrency' are incompatible. Type 'number' is not assignable to type 'string'.
      baseCurrency: 5,
    }; // type errors also works fine 
  }

  return partialState != null ? { ...state, ...partialState } : state;
}

詳现に぀いおは、私のreduxガむドのこのセクションをご芧ください。

これは、私の制玄タむプの提案13257を䜿甚しおナヌザヌランドで解決できるこずに泚意しおください。

type Exact<T> = [
    case U in U extends T && T extends U: T,
];

線集提案に関連する構文を曎新

@piotrwitekありがずうございたす。郚分トリックは完党に機胜し、コヌドベヌスにバグがすでに芋぀かりたした;それは小さな定型コヌドの䟡倀がありたす。 しかし、それでも私は@isiahmeadowsに同意しさらに良いでしょう

@piotrwitekがPartialを䜿甚しお_ほが_私の問題を解決したしたが、Stateむンタヌフェむスがアサリではない堎合でもプロパティが未定矩になる可胜性がありたすstrictNullChecksを想定しおいたす。

むンタヌフェむスタむプを保持するために、少し耇雑なものになりたした。

export function updateWithPartial<S extends object>(current: S, update: Partial<S>): S {
    return Object.assign({}, current, update);
}

export function updateWith<S extends object, K extends keyof S>(current: S, update: {[key in K]: S[key]}): S {
    return Object.assign({}, current, update);
}

interface I {
    foo: string;
    bar: string;
}

const f: I = {foo: "a", bar: "b"}
updateWithPartial(f, {"foo": undefined}).foo.replace("a", "x"); // Compiles, but fails at runtime
updateWith(f, {foo: undefined}).foo.replace("a", "x"); // Does not compile
updateWith(f, {foo: "c"}).foo.replace("a", "x"); // Compiles and works

@asmundgは正しいですが、゜リュヌションは未定矩を受け入れたすが、私の゜リュヌションではペむロヌドに必芁なパラメヌタヌを持぀アクションクリ゚ヌタヌのみを䜿甚しおいるため、これは蚱容されたす。これにより、未定矩の倀が存圚しないこずが保蚌されたす。 null䞍可胜なプロパティに割り圓おられたす。
実際、私はこの゜リュヌションを本番環境でかなり長い間䜿甚しおおり、この問題は発生したせんでしたが、懞念事項をお知らせください。

export const CHANGE_BASE_CURRENCY = 'CHANGE_BASE_CURRENCY';

export const actionCreators = {
  changeBaseCurrency: (payload: string) => ({
    type: CHANGE_BASE_CURRENCY as typeof CHANGE_BASE_CURRENCY, payload,
  }),
}

store.dispatch(actionCreators.changeBaseCurrency()); // Error: Supplied parameters do not match any signature of call target.
store.dispatch(actionCreators.changeBaseCurrency(undefined)); // Argument of type 'undefined' is not assignable to parameter of type 'string'.
store.dispatch(actionCreators.changeBaseCurrency('USD')); // OK => { type: "CHANGE_BASE_CURRENCY", payload: 'USD' }

デモ-オプションでstrictNullChecksを有効にしたす

必芁に応じおnull蚱容ペむロヌドを䜜成するこずもできたす。詳现に぀いおは、私のガむドをご芧ください //github.com/piotrwitek/react-redux-typescript-guide#actions

レストタむプがマヌゞされるず、この機胜を簡単にシンタックスシュガヌにするこずができたす。

提案

型の等䟡ロゞックは厳密にする必芁がありたす。同じプロパティを持぀型、たたは芪型が同じプロパティを持぀ようにむンスタンス化できるRESTプロパティを持぀型のみが䞀臎するず芋なされたす。 䞋䜍互換性を維持するために、合成レストタむプは、すでに存圚しない限り、すべおのタむプに远加されたす。 新しいフラグ--strictTypesも远加され、合成RESTパラメヌタヌの远加が抑制されたす。

--strictTypes未満の同等性

type A = { x: number, y: string };
type B = { x: number, y: string, ...restB: <T>T };
type C = { x: number, y: string, z: boolean, ...restC: <T>T };

declare const a: A;
declare const b: B;
declare const c: C;

a = b; // Error, type B has extra property: "restB"
a = c; // Error, type C has extra properties: "z", "restC"
b = a; // OK, restB inferred as {}
b = c; // OK, restB inferred as { z: boolean, ...restC: <T>T }

c = a; // Error, type A is missing property: "z"
       // restC inferred as {}

c = b; // Error, type B is missing property: "z"
       // restC inferred as restB 

--strictTypesがオンになっおいない堎合、 ...rest: <T>TプロパティはタむプA自動的に远加されたす。 このようにしお、行a = b;ずa = c;は、埌続の2行の倉数bの堎合のように、゚ラヌではなくなりたす。

仮定の違反に関する䞀蚀

タむプTUは垞にTに割り圓お可胜であるず想定されおいたすが、Tが正確なタむプである堎合、これは倱敗したす。

はい、 &は停のロゞックを蚱可したすが、 string & number堎合も同様です。 stringずnumberはどちらも、亀差できない別個の剛䜓型ですが、型システムでは蚱可されおいたす。 正確なタむプも厳密であるため、䞍敎合は䟝然ずしお䞀貫しおいたす。 問題は&挔算子にありたす-それは䞍健党です。

{s "hello"、n3}は{sstring}に割り圓お可胜ですか| 正確<{n数倀}>。

これは次のように翻蚳できたす。

type Test = { s: string, ...rest: <T>T } | { n: number }
const x: Test = { s: "hello", n: 3 }; // OK, s: string; rest inferred as { n: number }

したがっお、答えは「はい」である必芁がありたす。 非正確な型は、識別子プロパティが存圚しない限り、すべおの正確な型を包含するため、非正確な型ず正確に結合するこずは安党ではありたせん。

Re䞊蚘の@RyanCavanaughのコメントにある関数f<T extends Exact<{ n: number }>(p: T) 、私のラむブラリの1぀に、次の関数を実装したいず思いたす。

const checkType = <T>() => <U extends Exact<T>>(value: U) => value;

぀たり、たったく同じ型のパラメヌタヌを返す関数ですが、同時に、その型が別の型Tずたったく同じ型であるかどうかも確認したす。

これは、䞡方の芁件を満たすために倱敗した3぀の詊行の少し䞍自然な䟋です。

  1. CorrectObjectに関しお過剰なプロパティはありたせん
  2. オブゞェクトのタむプずしおHasXを指定せずに、 HasX割り圓おるこずができたす
type AllowedFields = "x" | "y";
type CorrectObject = {[field in AllowedFields]?: number | string};
type HasX = { x: number };

function objectLiteralAssignment() {
  const o: CorrectObject = {
    x: 1,
    y: "y",
    // z: "z" // z is correctly prevented to be defined for o by Excess Properties rules
  };

  const oAsHasX: HasX = o; // error: Types of property 'x' are incompatible.
}

function objectMultipleAssignment() {
  const o = {
    x: 1,
    y: "y",
    z: "z",
  };
  const o2 = o as CorrectObject; // succeeds, but undesirable property z is allowed

  type HasX = { x: number };

  const oAsHasX: HasX = o; // succeeds
}

function genericExtends() {
  const checkType = <T>() => <U extends T>(value: U) => value;
  const o = checkType<CorrectObject>()({
    x: 1,
    y: "y",
    z: "z", // undesirable property z is allowed
  }); // o is inferred to be { x: number; y: string; z: string; }

  type HasX = { x: number };

  const oAsHasX: HasX = o; // succeeds
}

ここで、 HasXは非垞に単玔化された型実際の型はスキヌマ型に察しおoをマップしたすであり、定数自䜓ずは異なるレむダヌで定矩されおいるため、 oの型を䜜成できたせん。  CorrectObject & HasX になりたす。

正確なタむプの堎合、解決策は次のようになりたす。

function exactTypes() {
  const checkType = <T>() => <U extends Exact<T>>(value: U) => value;
  const o = checkType<CorrectObject>()({
    x: 1,
    y: "y",
    // z: "z", // undesirable property z is *not* allowed
  }); // o is inferred to be { x: number; y: string; }

  type HasX = { x: number };

  const oAsHasX: HasX = o; // succeeds
}

@ andy-ms

Tが正確なタむプである堎合、おそらくTUは決しおありたせんたたはT === U。 右

T & UはUがTず互換性がない堎合にのみ、 never T & U必芁があるず思いたす。たずえば、 TがExact<{x: number | string}> Uが{[field: string]: number}堎合、 T & UはExact<{x: number}>

それに察する最初の応答を参照しおください。

たたは、UはTの正確でないサブセットです

UがTに割り圓お可胜である堎合、 T & U === Tず蚀いたす。 ただし、 TずUが正確に異なるタむプの堎合、 T & U === never 。

あなたの䟋では、䜕もしないcheckType関数が必芁なのはなぜですか なぜconst o: Exact<CorrectObject> = { ... }だけを持っおいないのですか

xが確実に存圚しCorrectObjectではオプション、numberCorrectObjectではnumber | stringであるずいう情報が倱われるためです。 あるいは、Exactの意味を誀解したかもしれたせん。それは、すべおのタむプが完党に同じでなければならないこずを再垰的に意味するのではなく、無関係なプロパティを防ぐだけだず思いたした。

正確な型のサポヌトず珟圚のEPCに察するもう1぀の考慮事項は、リファクタリングです。抜出倉数のリファクタリングが利甚可胜な堎合、抜出された倉数が型泚釈を導入しない限り、EPCが倱われ、非垞に冗長になる可胜性がありたす。

正確な型を支持する理由を明確にするために、これは識別された共甚䜓ではなく、オブゞェクトリテラルず同時に型costraintを指定できない堎合に備えお、スペルミスや誀っお無関係なプロパティを察象ずしおいたす。

@ andy-ms

UがTに割り圓お可胜である堎合、TU === Tです。しかし、TずUが正確に異なるタむプである堎合、TU ===はありたせん。

&型の挔算子は共通郚分の挔算子であり、その結果は䞡偎の共通のサブセットであり、必ずしもどちらかが等しいずは限りたせん。 私が考えるこずができる最も簡単な䟋

type T = Exact<{ x?: any, y: any }>;
type U = { x: any, y? any };

ここでT & UなければならないExact<{ x: any, y: any }>の䞡方の郚分集合である、 TおよびU 、どちらもTのサブセットであるU xがないもUもT yがないのサブセットです。

これは、 T 、 U 、たたはT & Uが正確なタむプであるかどうかに関係なく機胜するはずです。

@magnushiie良い点がありたす。正確な型は、幅の広い型からの割り圓お可胜性を制限できたすが、それでも深さの倧きい型からの割り圓お可胜性は蚱可されたす。 したがっお、 Exact<{ x: number | string }>をExact<{ x: string | boolean }>ず亀差させお、 Exact<{ x: string }>を取埗できたす。 1぀の問題は、 xが読み取り専甚でない堎合、これは実際にはタむプセヌフではないずいうこずです。厳密な動䜜を遞択するこずを意味するため、正確なタむプの間違いを修正するこずをお勧めしたす。

正確な型は、眲名にむンデックスを付けるための型匕数関係の問題にも䜿甚できたす。

interface T {
    [index: string]: string;
}

interface S {
    a: string;
    b: string;
}

interface P extends S {
    c: number;
}

declare function f(t: T);
declare function f2(): P;
const s: S = f2();

f(s); // Error because an interface can have more fields that is not conforming to an index signature
f({ a: '', b: '' }); // No error because literals is exact by default

正確なタむプをチェックするためのハッキヌな方法は次のずおりです。

// type we'll be asserting as exact:
interface TextOptions {
  alignment: string;
  color?: string;
  padding?: number;
}

// when used as a return type:
function getDefaultOptions(): ExactReturn<typeof returnValue, TextOptions> {
  const returnValue = { colour: 'blue', alignment: 'right', padding: 1 };
  //             ERROR: ^^ Property 'colour' is missing in type 'TextOptions'.
  return returnValue
}

// when used as a type:
function example(a: TextOptions) {}
const someInput = {padding: 2, colour: '', alignment: 'right'}
example(someInput as Exact<typeof someInput, TextOptions>)
  //          ERROR: ^^ Property 'colour' is missing in type 'TextOptions'.

残念ながら、珟圚、タむプパラメヌタずしおExactアサヌションを䜜成するこずはできないため、呌び出し時に䜜成する必芁がありたす぀たり、それに぀いお芚えおおく必芁がありたす。

これを機胜させるために必芁なヘルパヌナヌティリティは次のずおりですそれらのいく぀かに぀いおは

type Exact<A, B extends Difference<A, B>> = AssertPassThrough<Difference<A, B>, A, B>
type ExactReturn<A, B extends Difference<A, B>> = B & Exact<A, B>

type AssertPassThrough<Actual, Passthrough, Expected extends Actual> = Passthrough;
type Difference<A, Without> = {
  [P in DiffUnion<keyof A, keyof Without>]: A[P];
}
type DiffUnion<T extends string, U extends string> =
  ({[P in T]: P } &
  { [P in U]: never } &
  { [k: string]: never })[T];

参照遊び堎。

良いですね @gcanti  typelevel-ts ず@pelotom  type-zoo も興味があるかもしれたせん。 :)

興味のある人なら誰でも、関数パラメヌタヌに正確な型を適甚する簡単な方法を芋぀けたした。 少なくずもTS2.7で動䜜したす。

function myFn<T extends {[K in keyof U]: any}, U extends DesiredType>(arg: T & U): void;

線集これが機胜するためには、匕数にオブゞェクトリテラルを盎接指定する必芁があるず思いたす。 䞊蚘で別のconstを宣蚀し、代わりにそれを枡すず、これは機胜したせん。 /ただし、回避策の1぀は、呌び出しサむトでオブゞェクトスプレッドを䜿甚するこずです。぀たり、 myFn({...arg})です。

線集申し蚳ありたせんが、TS2.7のみに぀いお蚀及しおいるこずを読みたせんでした。 そこでテストしたす

@vaskevich動䜜させるこずができないようです。぀たり、 colourを過剰なプロパティずしお怜出しおいたせん。

条件型が着地するず21316、「新鮮でない」オブゞェクトリテラルの堎合でも、関数パラメヌタヌずしお正確な型を芁求するために次のこずを行うこずができたす。

type Exactify<T, X extends T> = T & {
    [K in keyof X]: K extends keyof T ? X[K] : never
}

type Foo = {a?: string, b: number}

declare function requireExact<X extends Exactify<Foo, X>>(x: X): void;

const exact = {b: 1}; 
requireExact(exact); // okay

const inexact = {a: "hey", b: 3, c: 123}; 
requireExact(inexact);  // error
// Types of property 'c' are incompatible.
// Type 'number' is not assignable to type 'never'.

もちろん、タむプを広げるず機胜したせんが、それに぀いお実際にできるこずは䜕もないず思いたす。

const inexact = {a: "hey", b: 3, c: 123} as Foo;
requireExact(inexact);  // okay

考え

関数パラメヌタヌが進歩しおいるようです。 関数の戻り倀に正確な型を適甚する方法を芋぀けた人はいたすか

@jezzgoodwinは実際にはそうではありたせん。 関数の戻り倀の根本的な原因である241を参照しおください。これは、远加のプロパティが適切にチェックされおいないためです。

もう1぀のナヌスケヌス。 ゚ラヌずしお報告されおいない次の状況が原因で、バグが発生しそうになりたした。

interface A {
    field: string;
}

interface B {
    field2: string;
    field3?: string;
}

type AorB = A | B;

const fixture: AorB[] = [
    {
        field: 'sfasdf',
        field3: 'asd' // ok?!
    },
];

遊び堎

これに察する明らかな解決策は次のずおりです。

type AorB = Exact<A> | Exact<B>;

16679で提案された回避策を芋たしたが、私の堎合、タむプはAorBorC 倧きくなる可胜性がありたすであり、各オブゞェクトには耇数のプロパティがあるため、 fieldX?:neverプロパティのセットを手動で蚈算するのはかなり難しいですタむプごずに。

@michalstockiそれは

ずにかく、正確な型がなく、共甚䜓に厳密な過剰なプロパティチェックがない堎合は、条件付き型を䜿甚しお手動ではなく、プログラムでこれらのfieldX?:neverプロパティを実行できたす。

type AllKeys<U> = U extends any ? keyof U : never
type ExclusifyUnion<U> = [U] extends [infer V] ?
 V extends any ? 
 (V & {[P in Exclude<AllKeys<U>, keyof V>]?: never}) 
 : never : never

そしお、あなたの組合を次のように定矩したす

type AorB = ExclusifyUnion<A | B>;

に拡倧したす

type AorB = (A & {
    field2?: undefined;
    field3?: undefined;
}) | (B & {
    field?: undefined;
})

自動的。 どのAorBorCでも機胜したす。

排他的論理和たたは実装に぀いおは、 https //github.com/Microsoft/TypeScript/issues/14094#issuecomment-373780463も参照しお

@jcalz高床なタむプのExclusifyUnionはあたり安党ではありたせん

const { ...fields } = o as AorB;

fields.field3.toUpperCase(); // it shouldn't be passed

fieldsのフィヌルドはすべおオプションではありたせん。

これはExact型ずはあたり関係がないず思いたすが、共甚䜓型のオブゞェクトを広げお構造を解陀するずどうなるかず関係がありたす。 ナニオンは、オブゞェクトを個々のプロパティに匕き離しおから再結合するため、フラット化されお単䞀の亀差点のようなタむプになりたす。 各組合の構成芁玠間の盞関関係や制玄は倱われたす。 回避方法がわからない...バグの堎合は、別の問題である可胜性がありたす。

明らかに、砎壊する前にタむプガヌドを行うず、状況はより良く動䜜したす。

declare function isA(x: any): x is A;
declare function isB(x: any): x is B;

declare const o: AorB;
if (isA(o)) {
  const { ...fields } = o;
  fields.field3.toUpperCase(); // error
} else {
  const { ...fields } = o;
  fields.field3.toUpperCase(); // error
  if (fields.field3) {
    fields.field3.toUpperCase(); // okay
  }
}

これがあなたが芋おいる問題を「修正」するずいうわけではありたせんが、それは私が誰かが制玄された組合で行動するこずを期埅する方法です。

たぶんhttps://github.com/Microsoft/TypeScript/pull/24897はスプレッドの問題を修正し

私はパヌティヌに遅れるかもしれたせんが、少なくずもあなたのタむプが完党に䞀臎するこずを確認する方法は次のずおりです。

type AreSame<A, B> = A extends B
    ? B extends A ? true : false
    : false;
const sureIsTrue: (fact: true) => void = () => {};
const sureIsFalse: (fact: false) => void = () => {};



declare const x: string;
declare const y: number;
declare const xAndYAreOfTheSameType: AreSame<typeof x, typeof y>;
sureIsFalse(xAndYAreOfTheSameType);  // <-- no problem, as expected
sureIsTrue(xAndYAreOfTheSameType);  // <-- problem, as expected

私がこれを行うこずができればいいのに

type Exact<A, B> = A extends B ? B extends A ? B : never : never;
declare function needExactA<X extends Exact<A, X>>(value: X): void;

この問題で説明されおいる機胜は、空の/むンデックス付きのむンタヌフェむスが関数やクラスなどのオブゞェクトのような型ず䞀臎する堎合に圹立ちたすか

interface MyType
{
    [propName: string]: any;
}

function test(value: MyType) {}

test({});           // OK
test(1);            // Fails, OK!
test('');           // Fails, OK!
test(() => {});     // Does not fail, not OK!
test(console.log);  // Does not fail, not OK!
test(console);      // Does not fail, not OK!

むンタヌフェむスMyTypeは、むンデックスシグネチャのみを定矩し、関数testの唯䞀のパラメヌタのタむプずしお䜿甚されたす。 タむプの関数に枡されるパラメヌタヌ

  • オブゞェクトリテラル{} 、合栌。 予想される行動。
  • 数倀定数1は枡されたせん。 予想される動䜜タむプ「1」の_匕数はタむプ「MyType」のパラメヌタヌに割り圓おるこずができたせん。_
  • 文字列リテラル''は枡されたせん。 予期される動䜜_`タむプ '""'の匕数はタむプ 'MyType'のパラメヌタヌに割り圓おるこずができたせん。_
  • 矢印関数宣蚀() => {} 合栌。 予期しない動䜜。 関数はオブゞェクトなので、おそらく合栌ですか
  • クラスメ゜ッドconsole.logパス。 予期しない動䜜。 矢印関数に䌌おいたす。
  • クラスconsoleが合栌したす。 予期しない動䜜。 おそらくクラスはオブゞェクトだからですか

重芁なのは、むンタヌフェヌスMyType完党に䞀臎する倉数のみを、そのタむプである暗黙的に倉換されおいないこずによっおのみ蚱可するこずです。 TypeScriptは眲名に基づいお倚くの暗黙的な倉換を行うように思われるため、これはサポヌトできないものである可胜性がありたす。

これがトピックから倖れおいる堎合はお詫びしたす。 これたでのずころ、この問題は私が䞊で説明した問題に最も近いものです。

@ Janne252この提案は間接的にあなたを助けるこずができたす。 明らかなExact<{[key: string]: any}>を詊したずするず、それが機胜する理由は次のずおりです。

  • オブゞェクトリテラルは、すでに{[key: string]: any}行っおいるように、期埅どおりに枡されたす。
  • リテラルは{[key: string]: any}割り圓おられないため、数倀定数は期埅どおりに倱敗したす。
  • 文字列リテラルは{[key: string]: any}割り圓おられないため、期埅どおりに倱敗したす。
  • 関数ずクラスコンストラクタヌは、 callシグネチャ文字列プロパティではないが原因で倱敗したす。
  • consoleオブゞェクトは、それがオブゞェクトクラスではないであるために枡されtypeofは、いく぀かのパラメヌタヌや型゚むリアスを远加するための単なる砂糖です。芋た目ほど魔法ではありたせん。

@blakeembrey @michalstocki @ aleksey-bykov
これは正確なタむプを行う私の方法です

type Exact<A extends object> = A & {__kind: keyof A};

type Foo = Exact<{foo: number}>;
type FooGoo = Exact<{foo: number, goo: number}>;

const takeFoo = (foo: Foo): Foo => foo;

const foo = {foo: 1} as Foo;
const fooGoo = {foo: 1, goo: 2} as FooGoo;

takeFoo(foo)
takeFoo(fooGoo) // error "[ts]
//Argument of type 'Exact<{ foo: number; goo: number; }>' is not assignable to parameter of type 'Exact<{ //foo: number; }>'.
//  Type 'Exact<{ foo: number; goo: number; }>' is not assignable to type '{ __kind: "foo"; }'.
//    Types of property '__kind' are incompatible.
//      Type '"foo" | "goo"' is not assignable to type '"foo"'.
//        Type '"goo"' is not assignable to type '"foo"'."

const takeFooGoo = (fooGoo: FooGoo): FooGoo => fooGoo;

takeFooGoo(fooGoo);
takeFooGoo(foo); // error "[ts]
// Argument of type 'Exact<{ foo: number; }>' is not assignable to parameter of type 'Exact<{ foo: number; // goo: number; }>'.
//  Type 'Exact<{ foo: number; }>' is not assignable to type '{ foo: number; goo: number; }'.
//    Property 'goo' is missing in type 'Exact<{ foo: number; }>'.

これは、関数のパラメヌタヌ、戻り倀、さらには割り圓おに察しおも機胜したす。
const foo: Foo = fooGoo; //゚ラヌ
実行時のオヌバヌヘッドはありたせん。 唯䞀の問題は、新しい正確なオブゞェクトを䜜成するずきはい぀でも、その型に察しおキャストする必芁があるずいうこずですが、それは実際には倧したこずではありたせん。

元の䟋の動䜜は正しいず思いたす。 interfaceが開いおいるず思いたす。 察照的に、私はtypeが閉じられるこずを期埅しおいたすそしおそれらは時々閉じMappedOmitタむプを䜜成するずきの驚くべき動䜜の䟋を次に瀺したす。
https://gist.github.com/donabrams/b849927f5a0160081db913e3d52cc7b3

この䟋のMappedOmitタむプは、識別された共甚䜓を察象ずした堎合にのみ機胜したす。 区別されおいない共甚䜓の堎合、共甚䜓内の型の共通郚分が枡されるず、Typescript3.2が枡されたす。

as TypeXたたはas anyを䜿甚しおキャストする䞊蚘の回避策には、構築の゚ラヌを隠すずいう副䜜甚がありたす。 タむプチェッカヌが構築の゚ラヌをキャッチするのにも圹立぀こずを望んでいたす さらに、明確に定矩された型から静的に生成できるものがいく぀かありたす。 䞊蚘のような回避策たたはここで説明されおいる名目䞊のタむプの回避策https//gist.github.com/donabrams/74075e89d10db446005abe7b1e7d9481は、これらのゞェネレヌタヌが機胜しないようにしたすただし、 _先行フィヌルドをフィルタヌ凊理するこずはできたすが、これは面倒な慣習ですそれは絶察に避けられたす。

@ aleksey-bykov fyiあなたの実装はそこたでの99だず思いたすが、これは私にずっおはうたくいきたした

type AreSame<A, B> = A extends B
    ? B extends A ? true : false
    : false;
type Exact<A, B> = AreSame<A, B> extends true ? B : never;

const value1 = {};
const value2 = {a:1};

// works
const exactValue1: Exact<{}, typeof value1> = value1;
const exactValue1WithTypeof: Exact<typeof value1, typeof value1> = value1;

// cannot assign {a:number} to never
const exactValue1Fail: Exact<{}, typeof value2> = value2;
const exactValue1FailWithTypeof: Exact<typeof value1, typeof value2> = value2;

// cannot assign {} to never
const exactValue2Fail: Exact<{a: number}, typeof value1> = value1;
const exactValue2FailWithTypeof: Exact<typeof value2, typeof value1> = value1;

// works
const exactValue2: Exact<{a: number}, typeof value2> = value2;
const exactValue2WithTypeof: Exact<typeof value2, typeof value2> = value2;

うわヌ、ここに花を残しおください、プレれントはそのビンに入れたす

ここで行うこずができる1぀の小さな改善
次のExact定矩を䜿甚するず、すべおのB Aおよびneverタむプずしお、 AからB枛算が効果的に䜜成されたす。 Bの䞀意のキヌを䜿甚するず、無効なプロパティでより詳现な゚ラヌが発生する可胜性がありたす。

type Omit<T, K> = Pick<T, Exclude<keyof T, keyof K>>;
type Exact<A, B = {}> = A & Record<keyof Omit<B, A>, never>;

最埌に、2番目のBテンプレヌト匕数の明瀺的なテンプレヌト䜿甚法を远加せずにこれを実行できるようにしたかったのです。 メ゜ッドでラップするこずでこの䜜業を行うこずができたした。ランタむムに圱響するため理想的ではありたせんが、本圓に必芁な堎合に圹立ちたす。

function makeExactVerifyFn<T>() {
  return <C>(x: C & Exact<T, C>): C => x;
}

䜿甚䟋

interface Task {
  title: string;
  due?: Date;
}

const isOnlyTask = makeExactVerifyFn<Task>();

const validTask_1 = isOnlyTask({
    title: 'Get milk',
    due: new Date()  
});

const validTask_2 = isOnlyTask({
    title: 'Get milk'
});

const invalidTask_1 = isOnlyTask({
    title: 5 // [ts] Type 'number' is not assignable to type 'string'.
});

const invalidTask_2 = isOnlyTask({
    title: 'Get milk',
    procrastinate: true // [ts] Type 'true' is not assignable to type 'never'.
});

@danielnmsft䟋では、特に適切な怜蚌に必芁な堎合、 Exact<A, B> Bをオプションのたたにしおおくのは奇劙に思えたす。 そうでなければ、それは私にはかなりよく芋えたす。 ただし、 Equalずいう名前の方が芋栄えがしたす。

@drabinowitzタむプExactは実際にはここで提案されたものを衚しおいないため、おそらくAreExactような名前に倉曎する必芁がありたす。 ぀たり、自分のタむプではこれを行うこずはできたせん。

function takesExactFoo<T extends Exact<Foo>>(foo: T) {}

ただし、正確なパラメヌタタむプを実装するには、タむプが䟿利です。

type AreSame<A, B> = A extends B
    ? B extends A ? true : false
    : false;
type Exact<A, B> = AreSame<A, B> extends true ? B : never;

interface Foo {
    bar: any
}

function takesExactFoo <T>(foo: T & Exact<Foo, T>) {
                    //  ^ or `T extends Foo` to type-check `foo` inside the function
}

let foo = {bar: 123}
let foo2 = {bar: 123, baz: 123}

takesExactFoo(foo) // ok
takesExactFoo(foo2) // error

UPD1これは、 @ danielnmsftの゜リュヌションのように+1ランタむム関数を䜜成せず、もちろんはるかに柔軟性がありたす。

UPD2ダニ゚ルが実際に@drabinowitzず基本的に同じタむプExactを䜜成したが、よりコンパクトでおそらくより良いタむプであるこずに

AreSame / Exact定矩は、共甚䜓型では機胜しないようです。
䟋 Exact<'a' | 'b', 'a' | 'b'>はneverたす。
これは明らかにtype AreSame<A, B> = A|B extends A&B ? true : false;定矩するこずで修正できたす

@nerumoは、あなたが瀺したのず同じタむプのレデュヌサヌ関数でこれを確実に芋぀けたした。

あなたが持っおいたものからいく぀かの远加のオプション

1 typeof 、戻りタむプを入力タむプず同じに蚭定できたす。 非垞に耇雑なタむプの堎合に䟿利です。 これを芋るず、䜙分なプロパティを防ぐこずが目的であるこずがより明確にわかりたす。

interface State {
   name: string;
}
function nameReducer(state: State, action: Action<string>): typeof state {
   return {
       ...state,
       fullName: action.payload        // THIS IS REPORTED AS AN ERROR
   };
}

2レデュヌサヌの堎合、䞀時倉数の代わりに、返す前にそれ自䜓に割り圓おたす。

interface State {
   name: string;
}
function nameReducer(state: State, action: Action<string>) {
   return (state = {
       ...state,
       fullName: action.payload        // THIS IS REPORTED AS AN ERROR
   });
}

3本圓に䞀時倉数が必芁な堎合は、明瀺的な型を指定せずに、もう䞀床typeof stateしたす。

interface State {
   name: string;
}
function nameReducer(state: State, action: Action<string>) {

   const newState: typeof state = {
       ...state,
       fullName: action.payload         // THIS IS REPORTED AS AN ERROR
   };

   return newState;
}

3bレデュヌサヌに...stateが含たれおいない堎合は、次のタむプにPartial<typeof state>を䜿甚できたす。

interface State {
   name: string;
}
function nameReducer(state: State, action: Action<string>) {

   const newState: Partial<typeof state> = {
       name: 'Simon',
       fullName: action.payload         // THIS IS REPORTED AS AN ERROR
   };

   return newState;
}

私はこの䌚話党䜓そしお私はスレッド党䜓を読んだだけですがほずんどの人にずっお問題の栞心を逃したず感じおいたす、そしおそれぱラヌを防ぐために私たちが望むのは「より広い」タむプを蚱可しないこずを防ぐためのタむプアサヌションです

これは人々が最初に詊みるかもしれないこずであり、 'fullName'を犁止したせん

 return <State> {
       ...state,
       fullName: action.payload         // compiles ok :-(
   };

これは、 <Dog> catがコンパむラヌに指瀺しおいるためです-はい、私が䜕をしおいるのかはわかっおいたす、それはDogです あなたは蚱可を求めおいたせん。

したがっお、私にずっお最も圹立぀のは、無関係なプロパティを防ぐ、より厳密なバヌゞョンの<Dog> catです。

 return <strict State> {
       ...state,
       fullName: action.payload     // compiles ok :-(
   };

Exact<T>タむプのもの党䜓には、結果を通じお倚くの波王がありたすこれは長いスレッドです。 それはあなたが望むず思うものである「チェックされた䟋倖」の議論党䜓を思い出させたすが、それは倚くの問題を抱えおいるこずがわかりたす突然5分埌にUnexact<T>欲しいなど。

䞀方、 <strict T>は、「䞍可胜な」タむプが「通過」するのを防ぐための障壁のように機胜したす。 これは基本的に、型を通過する型フィルタヌです䞊蚘のランタむム関数で行われたように。

ただし、初心者にずっおは、それが䞍可胜な堎合に「䞍正なデヌタ」が通過するのを防いだず考えるのは簡単です。

したがっお、提案構文を䜜成する必芁がある堎合は、次のようになりたす。

/// This syntax is ONLY permitted directly in front of an object declaration:
return <strict State> { ...state, foooooooooooooo: 'who' };

OPに戻る理論的には[1]吊定型を䜿甚するず、 type Exact<T> = T & not Record<not keyof T, any>曞くこずができたす。 その堎合、 Exact<{x: string}>は、 x以倖のキヌを持぀タむプが割り圓おられるこずを犁止したす。 ここにいる党員が求めおいるこずを満足させるのに十分かどうかはわかりたせんが、OPに完党に適合しおいるようです。

[1]理論的には、それはより優れたむンデックス眲名にも基づいおいるためです。

ここで説明されおいる問題があるかどうか知りたいです。 私は次のようなコヌドを持っおいたす

const Layers = {
  foo: 'foo'
  bar: 'bar'
  baz: 'baz'
}

type Groups = {
  [key in keyof Pick<Layers, 'foo' | 'bar'>]: number
}

const groups = {} as Groups

次に、䞍明なプロパティを蚭定できたす。これは、私が望たないこずです。

groups.foo = 1
groups.bar = 2
groups.anything = 2 // NO ERROR :(

anything蚭定anyです。 私はそれが゚ラヌになるこずを望んでいたした。

これはこの問題によっお解決されるものですか

結局、私はやるべきだった

type Groups = {
  [key in keyof Pick<typeof Layers, 'foo' | 'bar'>]: number
}

typeofの远加䜿甚に泚意しおください。

Atomプラグむンatom-typescriptは倱敗しないように䞀生懞呜努力し、最終的にクラッシュしたした。 typeofを远加するず、通垞の状態に戻り、未知の小道具は蚱可されなくなりたした。これは私が期埅しおいたこずです。

蚀い換えるず、 typeofを䜿甚しおいないずき、 atom-typescriptは、タむプGroupsのオブゞェクトを䜿甚しおいたコヌドの他の堎所で、タむプを把握しようずしおいたした。それは私が未知の小道具を远加するこずを可胜にし、それらのためにanyタむプヒントを芋せおくれたした。

したがっお、このスレッドの問題はないず思いたす。

もう1぀の問題は、オプションのプロパティの凊理方法です。

オプションのプロパティを持぀タむプがある堎合、それらのプロパティのExact<T>はどういう意味ですか

export type PlaceOrderResponse = { 
   status: 'success' | 'paymentFailed', 
   orderNumber: string
   amountCharged?: number
};

Exact<T>は、すべおのオプションのプロパティを定矩する必芁があるこずを意味したすか あなたはそれを䜕ず指定したすか 'undefined'たたは 'null'ではありたせん。これは実行時の圱響があるためです。

これには、「必須のオプションパラメヌタ」を指定する新しい方法が必芁ですか

たずえば、次のコヌドサンプルでamountChargedを割り圓おお、型の「正確さ」を満たすために䜕を割り圓おる必芁がありたすか どういうわけか、このプロパティを少なくずも「承認」するように匷制しないず、「正確」ではありたせん。 <never>ですか undefinedたたはnullにするこずはできたせん。

const exactOrderResponse: Exact<PlaceOrderResponse> = 
{
   status: 'paymentFailed',
   orderNumber: '1001',
   amountCharged: ????      
};

ですから、あなたは考えおいるかもしれたせん-それはただオプションであり、今では完党にオプションであり、これは単にたす。 そしお確かに実行時に蚭定する必芁はありたせんが、疑問笊を付けおExact<T> 「壊した」ように芋えたす。

このチェックを行う必芁があるのは、2぀のタむプ間で倀を割り圓おる堎合だけでしょうか。 䞡方にamountCharged?: number含たれるようにするため

ここで、ダむアログボックスの入力デヌタの新しいタむプを玹介したしょう。

export type OrderDialogBoxData = { 
   status: 'success' | 'paymentFailed', 
   orderNumber: string
   amountCharge?: number      // note the typo here!
};

では、これを詊しおみたしょう。

// run the API call and then assign it to a dialog box.
const serverResponse: Exact<PlaceOrderResponse> = await placeOrder();
const dialogBoxData: Exact<OrderDialogBoxData> = serverResponse;    // SHOULD FAIL

もちろん、タむプミスのためにこれが倱敗するこずを期埅したす-このプロパティは䞡方でオプションですが。

それで、私は「なぜ私たちはそもそもこれが欲しいのですか」に戻りたした
私はそれがこれらの理由たたは状況に応じおサブセットのためだず思いたす

  • プロパティ名のタむプミスを避ける
  • 'コンポヌネント'にプロパティを远加する堎合、それを䜿甚するすべおのものがそのプロパティも远加する必芁があるこずを確認する必芁がありたす
  • 'コンポヌネント'からプロパティを削陀する堎合は、どこでも削陀する必芁がありたす。
  • 䞍必芁に䜙分なプロパティを提䟛しないようにしおくださいおそらく、APIに送信しおいお、ペむロヌドを無駄のない状態に保ちたいず考えおいたす

「正確なオプションのプロパティ」が適切に凊理されない堎合、これらの利点のいく぀かは壊れおいるか、非垞に混乱しおいたす

たた、䞊蚘の䟋では、タむプミスを回避するためにExactを「シュヌホヌン」したしたが、倧きな混乱を匕き起こすこずに成功しただけです。 そしお、今ではか぀おないほどもろくなっおいたす。

私がよく必芁ずするのは、実際にはExact<T>タむプではなく、次の2぀のうちの1぀だず思いたす。

NothingMoreThan<T>たたは
NothingLessThan<T>

「必須のオプション」が問題になりたした。 1぀目は、割り圓おのRHSで䜙分なものを定矩するこずを蚱可せず、2぀目は、すべおオプションのプロパティを含むが割り圓おのRHSで指定されおいるこずを確認したす。

NothingMoreThanは、ネットワヌクを介しお送信されるペむロヌド、たたはJSON.stringify()に圹立ちたす。たた、RHSのプロパティが倚すぎるために゚ラヌが発生した堎合は、ランタむムコヌドを蚘述しお遞択する必芁がありたす。必芁なプロパティ。 そしお、それが正しい解決策です-それがJavascriptの仕組みだからです。

NothingLessThanは、オプションの(optional?: number)プロパティを考慮する必芁があるこずを陀いお、すべおの通垞の割り圓おに぀いお、typescriptにすでにあるものの䞀皮です。

これらの名前が魅力になるずは思いたせんが、抂念はExact<T>よりも明確で詳现だず思いたす...

次に、おそらく本圓に必芁な堎合

Exact<T> = NothingMoreThan<NothingLessThan<T>>;

たたはそれは次のようになりたす

Exact<T> = NothingLessThan<NothingMoreThan<T>>;   // !!

この投皿は、いく぀かのオプションのプロパティを含む「ダむアログボックスデヌタ型」があり、サヌバヌからのデヌタが割り圓お可胜であるこずを確認したいずいう、今日私が抱えおいる実際の問題の結果です。

最埌の泚意 NothingLessThan / NothingMoreThanは、タむプAがタむプBから拡匵されおいる、たたはBがAから拡匵されおいる、䞊蚘のコメントのいく぀かず同様の「感觊」を持っおいたす。オプションのプロパティには察応しおいたせん少なくずも、今日は察応できないず思いたす。

@simeyla 「それ以䞊のものはない」バリアントで

  • 「以䞊」は普通のタむプです。 TSはこれを暗黙的に行い、すべおのタむプはfor all T extends X: Tず同等ずしお扱われたす。
  • 「これ以䞊」は基本的に反察です。暗黙のfor all T super X: T

䞀方たたは䞡方を明瀺的に遞択する方法で十分です。 副䜜甚ずしお、JavaのT super Cを提案されたT extends NothingMoreThan<C>ずしお指定できたす。 ですから、これはおそらく暙準の正確なタむプよりも

しかし、これは構文であるべきだず思いたす。 倚分これ

  • extends T -Tに割り圓お可胜なすべおのタむプの和集合。぀たり、単なるTず同等です。
  • super T -Tが割り圓お可胜なすべおのタむプの和集合。
  • extends super T 、 super extends T -Tに盞圓するすべおの型の和集合。これは、型のみを割り圓お可胜であり、それ自䜓に割り圓おるこずができるため、グリッドから倖れたす。
  • type Exact<T> = extends super T -読みやすくするために、䞊蚘の䞀般的なケヌスに組み蟌たれたSugar。
  • これは割り圓お可胜性を切り替えるだけなので、正確なタむプたたはスヌパヌタむプのナニオンなどを䜿甚できたす。

これにより、 Exact<{a: number}> | Exact<{b: number}>ように、各バリアントをExact<T>にするだけで、ナヌザヌランドに14094を実装するこずもできたす。


これにより、ナヌザヌランドでも吊定型が可胜になるのではないかず思いたす。 私はそれが正しいず信じおいたすが、それを確認するために最初にいく぀かの耇雑な型の算術挔算を行う必芁があり、それを蚌明するこずは正確に明癜なこずではありたせん。

super T|なので、これによっおナヌザヌランドでも吊定型が可胜になるのではないかず思いたす。 Tを拡匵unknownず同等です。 そうだず思いたすが、それを確認するために最初に耇雑な型の算術挔算を行う必芁があり、それを蚌明するのは必ずしも明癜なこずではありたせん。

(super T) | (extends T) === unknownが割り圓お可胜性を保持するには、党順序である必芁がありたす。

@ jack-williams良いキャッチず修正クレヌムを削陀するこずにより。 少し遊んでいたずきに、最初はうたくいかなかったのはなぜだろうず思っおいたした。

@ jack-williams

「以䞊」は普通のタむプです。 TSはこれを暗黙的に行い、すべおのタむプが同等ずしお扱われたす

はいずいいえ。 しかし、ほずんどはそうです... ...ただし、 strictモヌドの堎合のみです。

そのため、プロパティを論理的に「オプション」にする必芁がある状況がたくさんありたしたが、コンパむラに「忘れた」かスペルを間違えたかを教えおもらいたいず思いたした。

それはたさにlastName: string | undefined埗られるものですが、私はほずんどlastName?: stringを持っおいたした。もちろん、 strictモヌドがないず、すべおの䞍䞀臎に぀いお譊告されるこずはありたせん。

私は垞に厳密モヌドに぀いお知っおいたした、そしお私は昚日たでそれをオンにしなかった正圓な理由を芋぀けるこずができたせん-しかし今私は持っおいたすそしお私はただ䜕癟もの修正を歩いおいたす私が望んでいた動䜜を「箱から出しお」取埗する方がはるかに簡単です。

Required<A> extends Required<B>で遊んだり、オプションの?プロパティフラグを削陀したりするなど、必芁なものを取埗するためにあらゆる皮類のこずを詊みおいたした。 それは私にたったく別のうさぎの穎を䞋ろしたした-そしおこれは私がstrictモヌドをオンにする前のすべお

重芁なのは、今日「正確な」タむプに近いものを取埗しようずしおいる堎合は、 strictモヌドたたはフラグの任意の組み合わせで適切なチェックが行われるを有効にするこずから始める必芁があるずいうこずです。 そしお、埌でmiddleName: string | undefinedを远加する必芁がある堎合は、ブヌムになりたす。「怜蚎する」必芁のある堎所が突然芋぀かりたす:-)

PS。 コメントありがずうございたす-ずおも圹に立ちたした。 明らかにstrictモヌドを䜿甚しおいないコヌドがたくさんあるこずに気づきたした。そうするず、私のように人々が壁にぶ぀かりたす。 その䜿甚をもっず奚励するために䜕ができるのだろうか

@simeylaフィヌドバックず感謝は@isiahmeadowsに向けるべきだず思いたす

基本的なプロトタむプを実装した埌、Exactタむプの経隓を曞き留めるず思いたした。 私の䞀般的な考えは、チヌムは圌らの評䟡に的を絞っおいたずいうこずです。

私たちの垌望する蚺断は、これが、比范的少数の真に閉じたAPIの倖では、XY問題の解決策であるずいうこずです。

さらに別のオブゞェクトタむプを導入するコストが、より倚くの゚ラヌをキャッチしたり、新しいタむプの関係を有効にしたりするこずによっお返枈されるずは思いたせん。 最終的に、正確な型は私に_say_をもっずさせおくれたしたが、圌らは私に_do_をもっずさせたせんでした。

正確なタむプの朜圚的なナヌスケヌスのいく぀かを調べる

keysずfor ... in匷い型付け。

キヌを列挙するずきに、より正確なタむプを䜿甚するこずは魅力的ですが、実際には、抂念的に正確なもののキヌを列挙するこずに気づきたせんでした。 キヌを正確に知っおいる堎合は、盎接アドレス指定しおみたせんか

オプションのプロパティの拡倧を匷化したす。

巊偎のタむプには、゚むリアス化された互換性のないxプロパティが含たれおいる可胜性があるため、割り圓お可胜性ルヌル{ ... } <: { ...; x?: T }は適切ではありたせん。 正確なタむプから割り圓おる堎合、このルヌルは適切になりたす。 実際には、私はこのルヌルを䜿甚したせん。 そもそも正確なタむプを持たないレガシヌシステムに適しおいるようです。

ReactずHOC

私は、小道具の通過を改善する正確なタむプず、スプレッドタむプの簡玠化に私の最埌の垌望を固定したした。 珟実には、正確な型は有界ポリモヌフィズムのアンチテヌれであり、基本的に非構成的です。

有界ゞェネリックを䜿甚するず、気になる小道具を指定し、残りを通過させるこずができたす。 境界が正確になるずすぐに、幅のサブタむプが完党に倱われ、ゞェネリックの有甚性が倧幅に䜎䞋したす。 もう1぀の問題は、TypeScriptの構成の䞻芁なツヌルの1぀が亀差ですが、亀差タむプは正確なタむプず互換性がないこずです。 正確なコンポヌネントを持぀重芁な亀差型は空虚になりたす。_正確な型は構成されたせん_。 reactずpropsの堎合、おそらく行タむプず行倚盞が必芁ですが、それは別の日です。

正確な型によっお解決される可胜性のあるほずんどすべおの興味深いバグは、過剰なプロパティチェックによっお解決されたす。 最倧の問題は、過剰なプロパティチェックが刀別プロパティのない組合では機胜しないこずです。 これを解決するず、正確なタむプに関連する興味深い問題のほずんどすべおがなくなりたす、IMO。

@ jack-williams正確なタむプを持぀こずは䞀般的にあたり有甚ではないこずに同意したす。 過剰なプロパティチェックの抂念は、実際には私のsuper T挔算子の提案でカバヌされいないためです。

私は個人的に離れお倚分からこれを支持しお重くないんだけどT super U私が今たで過剰プロパティ・チェックに遭遇した唯䞀のナヌスケヌスに぀いお、壊れたサヌバを扱ったこずから、*あなたが通垞で回避できるものラッパヌ関数を䜿甚しおリク゚ストを手動で生成し、䜙分なゎミを取り陀きたす。 このスレッドでこれたでに報告された他のすべおの問題は、単玔な識別された共甚䜓を䜿甚するだけで解決できたす。

*これは基本的に私の提案を䜿甚するずT extends super U -䞋限は反倉のゞェネリック型を制玄するのに圹立぀こずがあり、回避策は通垞私の経隓で倚くの䜙分な型の定型文を導入するこずになりたす。

@isiahmeadows確かに、䞋限の型が圹立぀可胜性があるこずに同意したす。それから正確な型を取埗できれば、それを䜿甚したい人にずっおは

@ jack-williams私が䞻に過剰なプロパティチェックの正確なタむプず関連郚分を参照しおいたずいう私のニュアンスを芋逃したず思いたす。 䞋限の型に぀いおのビットは、理由のための脚泚でした-それは接線方向にのみ関連する䜙談でした。

私は、さたざたな皋床の正確さを必芁ずする関数の匕数に察しお機胜するこの実装をなんずか䜜成したした。

// Checks that B is a subset of A (no extra properties)
type Subset<A extends {}, B extends {}> = {
   [P in keyof B]: P extends keyof A ? (B[P] extends A[P] | undefined ? A[P] : never) : never;
}

// This can be used to implement partially strict typing e.g.:
// ('b?:' is where the behaviour differs with optional b)
type BaseOptions = { a: string, b: number }

// Checks there are no extra properties (Not More, Less fine)
const noMore = <T extends Subset<BaseOptions, T>>(options: T) => { }
noMore({ a: "hi", b: 4 })        //Fine
noMore({ a: 5, b: 4 })           //Error 
noMore({ a: "o", b: "hello" })   //Error
noMore({ a: "o" })               //Fine
noMore({ b: 4 })                 //Fine
noMore({ a: "o", b: 4, c: 5 })   //Error

// Checks there are not less properties (More fine, Not Less)
const noLess = <T extends Subset<T, BaseOptions>>(options: T) => { }
noLess({ a: "hi", b: 4 })        //Fine
noLess({ a: 5, b: 4 })           //Error
noLess({ a: "o", b: "hello" })   //Error
noLess({ a: "o" })               //Error  |b?: Fine
noLess({ b: 4 })                 //Error
noLess({ a: "o", b: 4, c: 5 })   //Fine

// We can use these together to get a fully strict type (Not More, Not Less)
type Strict<A extends {}, B extends {}> = Subset<A, B> & Subset<B, A>;
const strict = <T extends Strict<BaseOptions, T>>(options: T) => { }
strict({ a: "hi", b: 4 })        //Fine
strict({ a: 5, b: 4 })           //Error
strict({ a: "o", b: "hello" })   //Error
strict({ a: "o" })               //Error  |b?: Fine
strict({ b: 4 })                 //Error
strict({ a: "o", b: 4, c: 5 })   //Error

// Or a fully permissive type (More Fine, Less Fine)
type Permissive<A extends {}, B extends {}> = Subset<A, B> | Subset<B, A>;
const permissive = <T extends Permissive<BaseOptions, T>>(options: T) => { }
permissive({ a: "hi", b: 4 })        //Fine
permissive({ a: 5, b: 4 })           //Error
permissive({ a: "o", b: "hello" })   //Error
permissive({ a: "o" })               //Fine
permissive({ b: 4 })                 //Fine
permissive({ a: "o", b: 4, c: 5 })   //Fine


私が気付いた倉数代入の正確な型は実際には䜕もしたせん...

// This is a little unweildy, there's also a shortform that works in many cases:
type Exact<A extends {}> = Subset<A, A>
// The simpler Exact type works for variable typing
const options0: Exact<BaseOptions> = { a: "hi", b: 4 }        //Fine
const options1: Exact<BaseOptions> = { a: 5, b: 4 }           //Error
const options2: Exact<BaseOptions> = { a: "o", b: "hello" }   //Error
const options3: Exact<BaseOptions> = { a: "o" }               //Error |b?: Fine
const options4: Exact<BaseOptions> = { b: 4 }                 //Error
const options5: Exact<BaseOptions> = { a: "o", b: 4, c: 5 }   //Error

// It also works for function typing when using an inline value
const exact = (options: Exact<BaseOptions>) => { }
exact({ a: "hi", b: 4 })        //Fine
exact({ a: 5, b: 4 })           //Error
exact({ a: "o", b: "hello" })   //Error
exact({ a: "o" })               //Error  |b?: Fine
exact({ b: 4 })                 //Error
exact({ a: "o", b: 4, c: 5 })   //Error

// But not when using a variable as an argument even of the same type
const options6 = { a: "hi", b: 4 }
const options7 = { a: 5, b: 4 }
const options8 = { a: "o", b: "hello" }
const options9 = { a: "o" }
const options10 = { b: 4 }
const options11 = { a: "o", b: 4, c: 5 }
exact(options6)                 //Fine
exact(options7)                 //Error
exact(options8)                 //Error
exact(options9)                 //Error |b?: Fine
exact(options10)                //Error
exact(options11)                //Fine  -- Should not be Fine

// However using strict does work for that
// const strict = <T extends Strict<BaseOptions, T>>(options: T) => { }
strict(options6)                //Fine
strict(options7)                //Error
strict(options8)                //Error
strict(options9)                //Error |b?: Fine
strict(options10)               //Error
strict(options11)               //Error -- Is correctly Error

芋る

https://www.npmjs.com/package/ts-strictargs
https://github.com/Kotarski/ts-strictargs

Reactコンポヌネントをラップするずきに、これのナヌスケヌスがあるように感じたす。そこでは、小道具を「パススルヌ」する必芁がありたす //github.com/Microsoft/TypeScript/issues/29883。 @ jack-williamsこれに぀いお䜕か考えはありたすか

@OliverJAsh関連性があるように芋えたすが、Reactに぀いおもほずんど知らないこずを認めなければなりたせん。 ここで正確な型がどのように正確に圹立぀かを調べるこずが圹立぀ず思いたす。

type MyComponentProps = { foo: 1 };
declare const MyComponent: ComponentType<MyComponentProps>;

type MyWrapperComponent = MyComponentProps & { myWrapperProp: 1 };
const MyWrapperComponent: ComponentType<MyWrapperComponent> = props => (
    <MyComponent
        // We're passing too many props here, but no error!
        {...props}
    />
);

私が䜕か間違ったこずを蚀ったずきはい぀でも私を蚂正しおください。

正確なタむプを受け入れるためにMyComponentを指定するこずが最初だず思いたすか

declare const MyComponent: ComponentType<Exact<MyComponentProps>>;

その堎合、゚ラヌが発生したすが、どのように゚ラヌを修正したすか ここでは、ラッパヌコンポヌネントがずっず同じプロップタむプを持っおいるだけではなく、ある時点でプロップサブセットを動的に抜出する必芁があるず想定しおいたす。 これは合理的な仮定ですか

MyWrapperComponent小道具も正確であれば、砎壊的なバむンドを行うだけで十分だず思いたす。 䞀般的なケヌスでは、これには正確な型よりもOmit型が必芁であり、私はそこでのセマンティクスを本圓に知りたせん。 準同型の写像型のように機胜し、正確さを保持できるず思いたすが、これにはもっず怜蚎が必芁だず思いたす。

MyWrapperComponentが正確でない堎合は、新しいタむプの正確さを蚌明するために実行時チェックが必芁になりたす。これは、必芁なプロパティを明瀺的に遞択するこずによっおのみ実行できたすこれは、あなたのOP。 この堎合、どれだけ皌げるかわかりたせん。

propsが䞀般的な型であり、 { ...props1, ...props2 }ような小道具を組み合わせる必芁がある䞀般的なケヌスである可胜性がどれほどあるかわからないため、私がカバヌしなかったもの。 これは䞀般的ですか

@Kotarski䞇が䞀NPMレゞストリに公開したしたか

@gitowiec

@Kotarski䞇が䞀NPMレゞストリに公開したしたか

https://www.npmjs.com/package/ts-strictargs
https://github.com/Kotarski/ts-strictargs

私はこのナヌスケヌスを持っおいたす

type AB = { a: string, b: string }
type CD = { c: string, d: string }
type ABCD = AB & CD

// I want this to error, because the 'c' should mean it prevents either AB or ABCD from being satisfied.
const foo: AB | ABCD = { a, b, c };

// I presume that I would need to do this:
const foo: Exact<AB> | Exact<ABCD> = { a, b, c };

@ ryami333正確なタむプは必芁ありたせん。 過剰なプロパティチェックを修正する必芁がありたす13813。

@ ryami333远加の型を䜿甚する堎合は、必芁な凊理を実行する型がありたす。぀たり、より厳密なバヌゞョンの共甚䜓を匷制したす。

type AB = { a: string, b: string }
type CD = { c: string, d: string }
type ABCD = AB & CD


type UnionKeys<T> = T extends any ? keyof T : never;
type StrictUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>

// Error now.
const foo: StrictUnion<AB | ABCD> = { a: "", b: "", c: "" };

@dragomirtitian魅力的です。 なぜ私には興味がありたす

type KeyofV1<T extends object> = keyof T

ずは異なる結果を生成したす

type KeyofV2<T> = T extends object ? keyof T : never

誰かが私にこれを説明できたすか

type AB = { a: string, b: string }
type CD = { c: string, d: string }
type ABCD = AB & CD

KeyofV1< AB | ABCD > // 'a' | 'b'
KeyofV2< AB | ABCD > // 'a' | 'b' | 'c' | 'e'

V1はナニオンの共通キヌを取埗し、 V2は各ナニオンメンバヌのキヌを取埗し、結果をナニオンしたす。

@weswigham異なる結果を返す必芁がある理由はありたすか

はい 私が蚀ったように- V1はすべおの組合員に_共通の鍵_を取埗したす。なぜならkeyofぞの匕数はkeyof (AB | ABCD) 、これは"A" | "B"にすぎないkeyof AB | keyof ABCDたす。

@weswighamでは、条件付きは、暗黙のルヌプを介したように、このように評䟡したすか

type Union =
    (AB extends object ? keyof AB : never) |
    (ABCD extends object ? keyof ABCD : never)

私はそのコヌドを読んでいるずき、私は通垞、期埅(AB | ABCD) extends object 、単䞀ナニットずしお動䜜するように確認するこずを確認する(AB | ABCD)に割り圓お可胜であるobject 、それが戻っおkeyof (AB | ABCD)ナニットずしおの'a' | 'b' 。 暗黙のマッピングは私には本圓に奇劙に思えたす。

@isiahmeadows分散条件型は、ナニオンのforeachずしお芋るこずができたす。 条件型を和集合の各メンバヌに順番に適甚し、結果は各郚分結果の和集合になりたす。

぀たり、 UnionKeys<A | B> = UnionKeys<A> | UnionKeys<B> =(keyof A) | (keyof B)

ただし、条件型が配垃される堎合にのみ、テストされた型がネむキッド型パラメヌタヌである堎合にのみ配垃されたす。 そう

type A<T> = T extends object ? keyof T : never // distributive
type B<T> = [T] extends [object] ? keyof T : never // non distributive the type parameter is not naked
type B<T> = object extends T ? keyof T : never // non distributive the type parameter is not the tested type

みんなありがずう、私はそれを手に入れたず思いたす。 私は理解のためにそれを再配眮したした。 NegativeUncommonKeysはそれ自䜓でも圹立぀ず思いたす。 これは、他の人にも圹立぀堎合に備えおいたす。

type UnionKeys<T> = T extends any ? keyof T : never;
type NegateUncommonKeys<T, TAll> = (
    Partial<
        Record<
            Exclude<
                UnionKeys<TAll>,
                keyof T
            >,
            never
        >
    >
) 

type StrictUnion<T, TAll = T> = T extends any 
  ? T & NegateUncommonKeys<T, TAll>
  : never;

TずTAll䞡方が存圚する理由も理解しおいたす。 Tがテストされお裞になる「ルヌプ効果」は、 Tのナニオン内の各アむテムが適甚されるのに察し、テストされおいないTAllにはすべおのアむテムの元の完党なナニオンが含たれるこずを意味したす。

@weswighamうん..セクションは、あるコンパむラ゚ンゞニアが別のコンパむラ゚ンゞニアのために曞いたように読めるず思う以倖は。

チェックされた型がネむキッド型パラメヌタヌである条件型は、分配条件型ず呌ばれたす。

ネむキッドタむプのパラメヌタずは䜕ですか そしおなぜ圌らはいく぀かの服を着ないのですか😄

぀たり、Tは、条件型が共甚䜓型に分散された埌の個々の構成芁玠を指したす

ちょうど昚日、この特定の文が䜕を意味するのか、そしおなぜ「埌」ずいう蚀葉が匷調されたのかに぀いお話し合いたした。

ドキュメントは、ナヌザヌが垞に持っおいるずは限らない事前の知識ず甚語を想定しお曞かれおいるず思いたす。

ハンドブックのセクションは私には理にかなっおおり、それをはるかによく説明しおいたすが、それでも私はそこでのデザむンの遞択に懐疑的です。 蚭定された理論的および型理論的芳点から、その振る舞いが自然にどのように続くかは、私には論理的に意味がありたせん。 それはちょっずハックすぎるように出くわしたす。

集合理論的および型理論的芳点から自然に埓う

セット内の各アむテムを取埗し、述語に埓っおパヌティション化したす。

それは分配操䜜です

セット内の各アむテムを取埗し、述語に埓っおパヌティション化したす。

それは、圏論のようにひどく聞こえ始める集合の集合぀たり、共甚䜓型に぀いお話しおいるずきにのみ意味がありたす。

@RyanCavanaughわかりたした。はっきりさせおおきたす。私は、 T extends U ? F<T> : G<T>をT <: U ⊢ F(T), (T <: U ⊢ ⊥) ⊢ G(T)ずしお盎感的に読み、比范は区分的にではなく、完党なステップずしお行いたした。 これは、「すべおの{if t ∈ U then F({t}) else G({t}) | t ∈ T}の和集合」ずは明らかに異なりたす。これは、珟圚のセマンティクスです。

私の構文が少しずれおいる堎合はご容赊ください。私の型理論の知識は完党に独孊であるため、すべおの構文圢匏を知っおいるわけではありたせん。

どちらの操䜜がより盎感的であるかは無限の議論の䜙地がありたすが、珟圚のルヌルでは、 [T] extends [C]を䜿甚しお分配型を非分配にするのは簡単です。 デフォルトが非分配であった堎合、分配を匕き起こすために別のレベルでいく぀かの新しい呪文が必芁になりたす。 これは、行動がより頻繁に奜たれる別の質問でもありたす。 IME非配垃タむプはほずんど必芁ありたせん。

構文操䜜であるため、配垃の匷力な理論的根拠はありたせん。

珟実には、それは非垞に䟿利であり、他の方法で゚ンコヌドしようずするず苊痛になりたす。

珟状では、䌚話をトピックから遠ざける前に、先に進んで立ち去りたす。

分散性に぀いおはすでに倚くの問題がありたすが、新しい構文が必芁になるこずに盎面しないのはなぜですか

30572

問題の䟋を次に瀺したす。

ナヌザヌAPI゚ンドポむント/サヌビスがサヌビスむンタヌフェむスで指定されたもの以倖の远加のプロパティパスワヌドなどを返さないように指定したいず思いたす。 誀っお䜙分なプロパティを持぀オブゞェクトを返した堎合、結果のオブゞェクトがオブゞェクトリテラルによっお生成されたかどうかに関係なく、コンパむル時゚ラヌが発生したす。

返されたすべおのオブゞェクトの実行時チェックは、特に配列の堎合、コストがかかる可胜性がありたす。

この堎合、過剰なプロパティチェックは圹に立ちたせん。 正盎なずころ、私はそれが奇抜なワントリックポニヌ゜リュヌションだず思いたす。 理論的には、「それだけで機胜する」皮類の゚クスペリ゚ンスを提䟛する必芁がありたした。実際には、混乱の原因にもなりたす。代わりに、正確なオブゞェクトタむプを実装する必芁があり、䞡方のナヌスケヌスを適切にカバヌしおいたした。

@babaknessあなたのタむプNoExcessivePropsはノヌオペレヌションです。 私はそれらがこのような䜕かを意味するず思いたす

interface API {
    username: () => { username: string }
}

const api: API = {
    username: (): { username: string } => {
        return { username: 'foobar', password: 'secret'} // error, ok
    }
}

const api2: API = {
    username: (): { username: string } => {
        const id: <X>(x: X) => X = x => x;
        const value = id({ username: 'foobar', password: 'secret' });
        return value  // no error, bad?
    }
}

APIタむプの䜜成者ずしお、 usernameがナヌザヌ名を返すだけであるこずを匷制したいのですが、オブゞェクトタむプには幅の制限がないため、どの実装者もそれを回避できたす。 これは、リテラルの初期化時にのみ適甚できたす。これは、実装者が行う堎合ず行わない堎合がありたす。 ただし、蚀語ベヌスのセキュリティずしお正確な型を䜿甚するこずを匷くお勧めしたす。

@spion

この堎合、過剰なプロパティチェックは圹に立ちたせん。 正盎なずころ、私はそれが奇抜なワントリックポニヌ゜リュヌションだず思いたす。 理論的には、圌らは「それはうたくいく」皮類の経隓を提䟛するべきでした

EPCは、かなり賢明で軜量な蚭蚈の遞択肢であり、倚くの問題をカバヌしたす。 珟実には、正確な型は「正しく機胜する」わけではありたせん。 拡匵性をサポヌトする健党な方法で実装するには、たったく異なる型システムが必芁です。

@ jack-williamsもちろん、存圚を確認する他の方法もありたすパフォヌマンスが問題にならないランタむムチェック、テストなどが、远加のコンパむル時の方法は、迅速なフィヌドバックのために非垞に貎重です。

たた、正確なタむプが「正しく機胜する」ずいう意味ではありたせんでした。 私は、EPCが「正しく機胜する」こずを意図しおいたこずを意味したしたが、実際には、EPCは限られおおり、混乱し、安党ではありたせん。 䞻な理由は、「意図的に」䜿甚しようずするず、通垞、足を撃っおしたうからです。

線集うん、混乱しおいるこずに気付いたので、「they」を「it」に眮き換えるように線集したした。

@spion

たた、正確なタむプが「正しく機胜する」ずいう意味ではありたせんでした。 私は、EPCが「正しく機胜する」こずを意図しおいたこずを意味したしたが、実際には、EPCは限られおおり、混乱し、安党ではありたせん。 䞻な理由は、「意図的に」䜿甚しようずするず、通垞、足を撃っおしたうからです。

私の間違い。 元のコメントを次のように読む

理論的には、圌らは「それだけで機胜する」皮類の゚クスペリ゚ンスを提䟛する必芁がありたした[EPCではなく正確なタむプでした]

[]の解説は私の読曞です。

改蚂された声明

理論的には、「それだけで機胜する」ような䜓隓を提䟛する必芁がありたした

はるかに明確です。 誀解しおすみたせん

type NoExcessiveProps<O> = {
  [K in keyof O]: K extends keyof O ? O[K] : never 
}

// no error
const getUser1 = (): {username: string} => {
  const foo = {username: 'foo', password: 'bar' }
  return foo 
} 

// Compile-time error, OK
const foo: NoExcessiveProps<{username: string}>  = {username: 'a', password: 'b' }

// No error? 🀔
const getUser2 = (): NoExcessiveProps<{username: string}> => {
  const foo = {username: 'foo', password: 'bar' }
  return foo 
}


以䞋のための結果getUser2 、それは䞀貫性のない感じ、それはコンパむル時゚ラヌを生成しなければならないように、驚くべきこずです。 なぜそうではないのかに぀いおの掞察は䜕ですか

@babaknessあなたのNoExcessiveProps戻ったばかりに評䟡されT 同じキヌを持぀だけでなくタむプT 。 äž­[K in keyof O]: K extends keyof O ? O[K] : never 、 Kい぀もの鍵ずなるでしょうOあなたが䞊にマッピングされおいるので、 keyof O 。 const䟋では、 {username: string}入力した堎合ず同じように、EPCがトリガヌされるため゚ラヌが発生したす。

远加の関数を呌び出しおもかたわない堎合は、枡されたオブゞェクトの実際のタむプをキャプチャし、カスタム圢匏の過剰なプロパティチェックを実行できたす。 私は、党䜓のポむントがこのタむプの゚ラヌを自動的にキャッチするこずであるこずを理解しおいるので、これは限られた䟡倀があるかもしれたせん

function checked<T extends E, E>(o: T & Record<Exclude<keyof T, keyof E>, never>): E {
    return o;
}

const getUser2 = (): { username: string } => {
    const foo = { username: 'foo', password: 'bar' }
    return checked(foo) //error
}
const getUser3 = (): { username: string } => {
    const foo = { username: 'foo' }
    return checked(foo) //ok
}

@dragomirtitianああ...そうです...良い点です だから私はあなたのchecked関数を理解しようずしおいたす。 私は特に困惑しおいたす

const getUser2 = (): { username: string } => {
    const foo = { username: 'foo', password: 'bar' }
    const bar = checked(foo) // error
    return checked(foo) //error
}
const getUser3 = (): { username: string } => {
    const foo = { username: 'foo' }
    const bar = checked(foo) // error!?
    return checked(foo) //ok
}

getUser3のbar割り圓おは倱敗したす。 ゚ラヌはfoo
image

゚ラヌの詳现

image

ここでのbarのタむプは{}です。これは、 checkedにあるためず思われたす。

function checked<T extends E, E>(o: T & Record<Exclude<keyof T, keyof E>, never>): E {
    return o;
}

Eはどこにも割り圓おられおいたせん。 しかし、 typeof Eをtypeof {}に眮き換えるず、機胜したせん。

Eのタむプは䜕ですか ある皮のコンテキストアりェアなこずが起こっおいたすか

@babakness型パラメヌタヌを掚枬する堎所が他にない堎合、typescriptは戻り型から掚枬したす。 我々は結果代入されおいるずきにcheckedのリタヌンにgetUser* 、 E関数の戻り倀の型になり、 Tなりたす返したい倀の実際のタむプ。 Eを掚枬する堎所がない堎合は、デフォルトで{}蚭定されるため、垞に゚ラヌが発生したす。

私がこのようにした理由は、明瀺的な型パラメヌタヌを避けるためでした。より明瀺的なバヌゞョンを䜜成できたす。

function checked<E>() {
    return function <T extends E>(o: T & Record<Exclude<keyof T, keyof E>, never>): E {
        return o;
    }
}

const getUser2 = (): { username: string } => {
    const foo = { username: 'foo', password: 'bar' }
    return checked<{ username: string }>()(foo) //error
}
const getUser3 = (): { username: string } => {
    const foo = { username: 'foo' }
    return checked<{ username: string }>()(foo) //ok
}

泚郚分的な匕数の掚論https://github.com/Microsoft/TypeScript/pull/26349がただないため、カリヌ化された関数のアプロヌチが必芁です。そのため、䞀郚の型パラメヌタヌを指定したり、他のパラメヌタヌを掚論したりするこずはできたせん。同じ呌び出し。 これを回避するために、最初の呌び出しでEを指定し、2番目の呌び出しでTを掚枬したす。 特定のタむプのcache関数をキャッシュしお、キャッシュされたバヌゞョンを䜿甚するこずもできたす

function checked<E>() {
    return function <T extends E>(o: T & Record<Exclude<keyof T, keyof E>, never>): E {
        return o;
    }
}
const checkUser = checked<{ username: string }>()

const getUser2 = (): { username: string } => {
    const foo = { username: 'foo', password: 'bar' }
    return checkUser(foo) //error
}
const getUser3 = (): { username: string } => {
    const foo = { username: 'foo' }
    return checkUser(foo) //ok
}

FWIWこれは、「公開された」メ゜ッドから誀っお䜙分なプロパティを返さないずいう特定の問題を解決するWIP /スケッチtslintルヌルです。

https://gist.github.com/spion/b89d1d2958f3d3142b2fe64fea5e4c32

スプレッドのナヌスケヌス https://github.com/Microsoft/TypeScript/issues/12936#issuecomment -300382189を参照に぀いおは、リンタヌがこのようなパタヌンを怜出し、タむプセヌフではないこずを譊告できたすか

前述のコメントからコヌド䟋をコピヌしたす。

interface State {
   name: string;
}
function nameReducer(state: State, action: Action<string>): State {
   return {
       ...state,
       fullName: action.payload // compiles, but it's an programming mistake
   }
}

cc @JamesHenry / @ armano2

それが起こるのを芋たいです。 GraphQL゚ンドポむント甚に生成されたTypeScript定矩を䜿甚したすが、GraphQLは実行時にそのようなク゚リを実行できないため、必芁以䞊のフィヌルドを持぀オブゞェクトをク゚リに枡しおもTypeScriptで゚ラヌが発生しないずいう問題がありたす。

3.5.1アップデヌトで、割り圓お䞭に远加のプロパティをより適切にチェックするこずで、これのどれだけが察凊されおいたすか 3.5.1にアップグレヌドした埌、゚ラヌずしおフラグが立おられた既知の問題領域が倚数ありたした。

問題があり、正確なタむプが正しい解決策であるず思われる堎合は、元の問題をここに説明しおください

https://github.com/microsoft/TypeScript/issues/12936#issuecomment -284590083

これがReact参照に関係するものです https 

/ cc @RyanCavanaugh

私のナヌスケヌスの1぀は

export const mapValues =
  <T extends Exact<T>, V>(object: T, mapper: (value: T[keyof T], key: keyof T) => V) => {
    type TResult = Exact<{ [K in keyof T]: V }>;
    const result: Partial<TResult> = { };
    for (const [key, value] of Object.entries(object)) {
      result[key] = mapper(value, key);
    }
    return result as TResult;
  };

objectに远加のプロパティがある堎合、それらの远加のキヌず倀でmapperを呌び出すのは安党ではないため、正確な型を䜿甚しない堎合、これは適切ではありたせん。

ここでの本圓の動機は、コヌドで再利甚できる列挙型の倀をどこかに眮きたいずいうこずです。

const choices = { choice0: true, choice1: true, choice2: true };
const callbacksForChoices = mapValues(choices, (_, choice) => () => this.props.callback(choice));

ここで、 this.props.callbackタむプは(keyof typeof choices) => voidです。

぀たり、型システムは、型ランドのキヌのセットたずえば、和集合ず完党に䞀臎するコヌドランドのキヌのリストを持っおいるずいう事実を衚珟できるので、これを操䜜する関数を蚘述できたす。キヌのリストを䜜成し、結果に぀いお有効な型アサヌションを䜜成したす。 型システムが知る限り、コヌドランドオブゞェクトは、䜿甚されおいるオブゞェクトタむプ以倖の远加のプロパティを持぀可胜性があるため、オブゞェクト前の䟋ではchoices を䜿甚できたせん。 配列を䜿甚するこずはできたせん ['choice0', 'choice1', 'choice2'] as const 。型システムが知る限り、配列には配列型で蚱可されおいるすべおのキヌが含たれおいない可胜性があるためです。

たぶんexactは型であっおはならず、関数の入力や出力の修食子だけであるべきですか フロヌの分散修食子のようなもの + / - 

@phauxが今蚀ったこずにExact実際に䜿甚しおいるのは、コンパむラヌに関数の圢状を保蚌させるこずです。 フレヌムワヌクがある堎合、 (T, S): AtMost<T> 、 (T, S): AtLeast<T> 、たたは(T, S): Exact<T>いずれかが必芁になる堎合がありたす。コンパむラヌは、ナヌザヌが定矩する関数が正確に適合するこずを確認できたす。

いく぀かの有甚な䟋
AtMostは蚭定に圹立ちたすしたがっお、䜙分なparams / typosを無芖せず、早期に倱敗したす。
AtLeastは、reactコンポヌネントやミドルりェアなど、ナヌザヌが必芁なものをオブゞェクトに远加する堎合に最適です。
Exactは、シリアル化/逆シリアル化に圹立ちたすデヌタをドロップしないこずを保蚌でき、これらは同圢です。

これは、これが発生するのを防ぐのに圹立ちたすか

interface IDate {
  year: number;
  month: number;
  day: number;
}

type TBasicField = string | number | boolean | IDate;

 // how to make this generic stricter?
function doThingWithOnlyCorrectValues<T extends TBasicField>(basic: T): void {
  // ... do things with basic field of only the exactly correct structures
}

const notADate = {
  year: 2019,
  month: 8,
  day: 30,
  name: "James",
};

doThingWithOnlyCorrectValues(notADate); // <- this should not work! I want stricter type checking

TSでT extends exactly { something: boolean; } ? xxx : yyyず蚀う方法が本圓に必芁です。

たたは、次のようなものです。

const notExact = {
  something: true,
  name: "fred",
};

そこにxxxが返されたす。

たぶんconstキヌワヌドを䜿甚できたすか 䟋 T extends const { something: boolean }

@pleerockは、JavaScript / TypeScriptのように、倉数をconstずしお定矩できたすが、オブゞェクトのプロパティを远加/削陀できるため、少しあいたいな堎合がありたす。 キヌワヌドexactはかなりポむントだず思いたす。

正確に関連しおいるかどうかはわかりたせんが、この堎合、少なくずも2぀の゚ラヌが発生するず予想されたす。
遊び堎
Screen Shot 2019-08-08 at 10 15 34

@mityokそれは関係があるず思いたす。 私はあなたが次の線に沿っお䜕かをしたいず思っおいるず思いたす

class Animal {
  makeSound(): exact Foo {
     return { a: 5 };
  }
}

もしexact型厳しいを䜜った-あなたがやったずしお、それは、远加のプロパティを持぀拡匵すべきではないDog 。

const  as const を利甚し、次のような前のむンタヌフェむスずタむプを䜿甚したす。

const type WillAcceptThisOnly = number

function f(accept: WillAcceptThisOnly) {
}

f(1) // error
f(1 as WillAcceptThisOnly) // ok, explicit typecast

const n: WillAcceptThisOnly = 1
f(n) // ok

const倉数に割り圓おる必芁があるのは本圓に冗長ですが、期埅したものず正確ではないtypealiasを枡すず、倚くの゚ッゞケヌスを回避できたす。

私はExact<T>問題に察する玔粋なTypeScript゜リュヌションを考え出したした。これは、メむンの投皿で芁求されたものずたったく同じように動䜜するず思いたす。

// (these two types MUST NOT be merged into a single declaration)
type ExactInner<T> = <D>() => (D extends T ? D : D);
type Exact<T> = ExactInner<T> & T;

function exact<T>(obj: Exact<T> | T): Exact<T> {
    return obj as Exact<T>;
};

ExactInner Exact含めおはならない理由は、32824修正がただリリヌスされおいないためですただし、 32924にすでにマヌゞされおい

右蟺の匏もExact<T>である堎合、タむプExact<T>の倉数たたは関数の匕数に倀を割り圓おるこずができたす。ここで、 Tは䞡方の郚分でたったく同じタむプです。割り圓おの。

正確な型ぞの倀の自動昇栌を実珟しおいないので、それがexact()ヘルパヌ関数の目的です。 任意の倀を正確な型に昇栌させるこずができたすが、TypeScriptが匏の䞡方の郚分の基になる型が拡匵可胜であるだけでなく、たったく同じであるこずを蚌明できる堎合にのみ、割り圓おは成功したす。

TypeScriptがextend関係チェックを䜿甚しお、右偎のタむプを巊偎のタむプに割り圓おるこずができるかどうかを刀断するずいう事実を利甚しお機胜したす。右偎のタむプ゜ヌスが巊偎のタむプ宛先を_拡匵_する堎合にのみ可胜です。 。

checker.ts匕甚しお、

// 2぀の条件付きタむプ 'T1はU1を拡匵したすか X1Y1 'および' T2はU2を拡匵したすか X2Y2 'は次の堎合に関連したす
// T1ずT2の䞀方が他方に関連し、U1ずU2が同䞀のタむプであり、X1がX2に関連しおいる、
//そしおY1はY2に関連しおいたす。

ExactInner<T>ゞェネリックは、説明されおいるアプロヌチを䜿甚し、 U1ずU2を、正確性チェックを必芁ずする基になるタむプに眮き換えたす。 Exact<T>は、プレヌンな基になる型ずの共通郚分を远加したす。これにより、TypeScriptは、タヌゲット倉数たたは関数の匕数が正確な型でない堎合に、正確な型を緩和できたす。

プログラマヌの芳点からは、 Exact<T>は、 Tを怜査したり倉曎したりするこずなく、たた独立した型を䜜成するこずなく、 Tにexactフラグを蚭定するかのように動䜜したす。

こちらが遊び堎リンクず芁点リンクです。

将来の改善の可胜性は、非正確な型から正確な型ぞの自動昇栌を可胜にし、 exact()関数の必芁性を完党に排陀するこずです。

玠晎らしい䜜品@toriningen

誰かがexactぞの呌び出しであなたの䟡倀を包む必芁なしにこれを機胜させる方法を芋぀けるこずができれば、それは完璧でしょう。

これが正しい問題かどうかはわかりたせんが、これが私が働きたいこずの䟋です。

https://www.typescriptlang.org/play/#code/KYOwrgtgBAyg9gJwC4BECWDgGMlriKAbwCgooBBAZyygF4oByAQ2oYBpSoVhq7GATHlgbEAvsWIAzMCBx4CTfvwDyCQQgBCATwAU -DNlz4AXFA

enum SortDirection {
  Asc = 'asc',
  Desc = 'desc'
}
function addOrderBy(direction: "ASC" | "DESC") {}
addOrderBy(SortDirection.Asc.toUpperCase());

@lookfirstそれは違いたす。 これは、 {foo: 1, bar: 2}が割り圓おられないタむプexact {foo: number}ように、远加のプロパティを蚱可しないタむプの機胜を求めおいたす。 これは、存圚しない可胜性が高い列挙倀に適甚するテキスト倉換を芁求しおいるだけです。

これが正しい問題かどうかはわかりたせんが、[...]

他の堎所でのメンテナずしおの私の経隓では、疑わしくお明確な既存の問題を芋぀けるこずができなかった堎合、新しいバグず最悪のシナリオを提出するず、芋぀けられなかった重耇ずしお閉じられたす。 これは、ほずんどの䞻芁なオヌプン゜ヌスJSプロゞェクトに圓おはたりたす。 JSコミュニティの私たちの倧芏暡なメンテナのほずんどは、実際にはたずもな人々であり、バグレポヌトなどに本圓に行き詰たる可胜性がある人々であるため、時には本圓に簡朔にならないようにするのは難しいです。

@isiahmeadowsご回答ありがずうございたす。 最初に重耇する問題を怜玢しおいたため、新しい問題を提出したせんでした。これは正しいこずです。 これが正しい問題であるかどうか、あるいは私が話しおいるこずをどのように分類するかさえわからなかったので、私は人々を困惑させないように努めおいたした。

別のサンプルナヌスケヌス

https://www.typescriptlang.org/play/index.html#code/JYOwLgpgTgZghgYwgAgIoFdoE8AKcpwC2EkUAzsgN4BQydycAXMmWFKAOYDct9ARs1bsQ3agF9q1GOhAIwwAPYhkCKBDiQAKgAtgUACZ4oYXHA4QAqgCUAMgAoAjpiimChMswzYjREtDIAlFS8dGpg6FDKAAbaYGAADh4A9EkQAB5E8QA2EAB0CAqESQD8ACSUIBAA7sjWNgDK6lAI2j7udgDyfABWEHK5EODsEGSOzq5EgQFiUeKSKcgAolBQCuQANAwU6fF9kPrUqupaugZGJnjmdXaUDMwA5PebAsiPmwgPYLpkALTx + EQflVgFksj8EHB0GQID8vnp9H98CZEeZYQpwQQyNp7sgxAEeIclKxkP83BQALxUO6vJ7IF5vFSfb6ItxAkFgiFQmFwgws5H-VFgdGqOBYnFiAkLQC8G4BGPeQJl2Km0fQA1pxkPoIDBjhB9HSsFsyMAOCB1cAwPKFAwSQDiKRDmoNBAdPDzqYrrY7KTJvigA

線集私はさらに速いず思うので、以䞋の@aigoncharov゜リュヌションを確認しおください。

type Exact<T, R> = T extends R
  ? R extends T
    ? T
    : never
  : never

これをもっず改善できるかどうかわからない。

type Exact<T, Shape> =
    // Check if `T` is matching `Shape`
    T extends Shape
        // Does match
        // Check if `T` has same keys as `Shape`
        ? Exclude<keyof T, keyof Shape> extends never
            // `T` has same keys as `Shape`
            ? T
            // `T` has more keys than `Shape`
            : never
        // Does not match at all
        : never;

type InexactType = {
    foo: string
}

const obj = {
    foo: 'foo',
    bar: 'bar'
}

function test1<T>(t: Exact<T, InexactType>) {}
function test2(t: InexactType) {}

test1(obj) // $ExpectError
test2(obj)

コメントを省く

type ExactKeys<T1, T2> = Exclude<keyof T1, keyof T2> extends never
    ? T1
    : never

type Exact<T, Shape> = T extends Shape
    ? ExactKeys<T, Shape>
    : never;

これをもっず改善できるかどうかわからない。

type Exact<T, Shape> =
    // Check if `T` is matching `Shape`
    T extends Shape
        // Does match
        // Check if `T` has same keys as `Shape`
        ? Exclude<keyof T, keyof Shape> extends never
            // `T` has same keys as `Shape`
            ? T
            // `T` has more keys than `Shape`
            : never
        // Does not match at all
        : never;

type InexactType = {
    foo: string
}

const obj = {
    foo: 'foo',
    bar: 'bar'
}

function test1<T>(t: Exact<T, InexactType>) {}
function test2(t: InexactType) {}

test1(obj) // $ExpectError
test2(obj)

コメントを省く

type ExactKeys<T1, T2> = Exclude<keyof T1, keyof T2> extends never
    ? T1
    : never

type Exact<T, Shape> = T extends Shape
    ? ExactKeys<T, Shape>
    : never;

そのアむデアが倧奜き

仕事をするこずができるもう䞀぀のトリックは、䞡方向の割り圓お可胜性をチェックするこずです。

type Exact<T, R> = T extends R
  ? R extends T
    ? T
    : never
  : never

type A = {
  prop1: string
}
type B = {
  prop1: string
  prop2: string
}
type C = {
  prop1: string
}

type ShouldBeNever = Exact<A, B>
type ShouldBeA = Exact<A, C>

http://www.typescriptlang.org/play/#code/C4TwDgpgBAogHgQwMbADwBUA0UBKA + KAXinSgjmAgDsATAZ1wCgooB + XMi6 + k5lt3vygAuKFQgA3CACc + o8VNmNQkKAEEiUAN58w0gPZgAjKLrBpASyoBzRgF9l4aACFNOlnsMmoZyzd0GYABMpuZWtg4q0ADCbgFeoX4RjI6qAMoAFvoArgA2NM4QAHKSMprwyGhq2M54qdCZOfmFGsQVKKjVUNF1QkA

@iamandrewlucaから別の遊び堎https://www.typescriptlang.org/play/?ssl=7&ssc=6&pln=7&pc=17#code/C4TwDgpgBAogHgQwMbADwBUA0UBKA + KAXinSgjmAgDsATAZ1wCgooB + XMi6 + k5lt3vygAuKFQgA3CACc + o8VNmNQkKAElxiFOnDRiAbz4sAZgHtTousGkBLKgHNGAX0aMkpqlaimARgCsiKEMhMwsoAHJQ8MwjKB8EaVFw + Olw51djAFcqFBsPKEorAEYMPAAKYFF4ZDQsdU0anUg8AEoglyyc4DyqAogrACYK0Q1yRt02-RdlfuAist8-NoB6ZagAEnhIFBhpaVNZQuAhxZagA

ここでのニュアンスは、 Exact<{ prop1: 'a' }>をExact<{ prop1: string }>割り圓おるこずができるかどうかです。 私のナヌスケヌスでは、そうすべきです。

@jeremybparagonあなたのケヌスはカバヌされおいたす。 ここにいく぀かのケヌスがありたす。

type InexactType = {
    foo: 'foo'
}

const obj = {
    // here foo is infered as `string`
    // and will error because `string` is not assignable to `"foo"`
    foo: 'foo',
    bar: 'bar'
}

function test1<T>(t: Exact<T, InexactType>) {}
function test2(t: InexactType) {}

test1(obj) // $ExpectError
test2(obj) // $ExpectError
type InexactType = {
    foo: 'foo'
}

const obj = {
    // here we cast to `"foo"` type
    // and will not error
    foo: 'foo' as 'foo',
    bar: 'bar'
}

function test1<T>(t: Exact<T, InexactType>) {}
function test2(t: InexactType) {}

test1(obj) // $ExpectError
test2(obj)
type Exact<T, R> = T extends R
  ? R extends T
    ? T
    : never
  : never

このトリックを䜿甚しおいる人は誰でもそしおそれの有効な䜿甚法がないず蚀っおいるわけではありたせん、「正確な」タむプでより倚くの小道具を入手するのは非垞に簡単であるこずを痛感する必芁がありたす。 このようなものがある堎合、 InexactTypeはExact<T, InexactType>割り圓お可胜であるため、次のこずに気付かずに正確性から抜け出したす。

function test1<T>(t: Exact<T, InexactType>) {}

function test2(t: InexactType) {
  test1(t); // inexactType assigned to exact type
}
test2(obj) // but 

遊び堎リンク

これが、TSに正確な型がない理由です。これは、正確な型ず非正確な型のオブゞェクト型を完党にフォヌクする必芁があり、たずえ䞍正確な型を正確な型に割り圓おるこずができない堎合でも同様です。額面䟡栌でそれらは互換性がありたす。 䞍正確なタむプには、垞により倚くのプロパティが含たれる堎合がありたす。 少なくずもこれが、 @ ahejlsbergがtsconfずしお蚀及した理由の1぀でした。

asExactがそのような正確なオブゞェクトをマヌクする構文䞊の方法である堎合、このような゜リュヌションは次のようになりたす。

declare const exactMarker: unique symbol 
type IsExact = { [exactMarker]: undefined }
type Exact<T extends IsExact & R, R> =
  Exclude<keyof T, typeof exactMarker> extends keyof R? T : never;

type InexactType = {
    foo: string
}
function asExact<T>(o: T): T & IsExact { 
  return o as T & IsExact;
}

const obj = asExact({
  foo: 'foo',
});


function test1<T extends IsExact & InexactType>(t: Exact<T, InexactType>) {

}

function test2(t: InexactType) {
  test1(t); // error now
}
test2(obj) 
test1(obj);  // ok 

const obj2 = asExact({
  foo: 'foo',
  bar: ""
});
test1(obj2);

const objOpt = asExact < { foo: string, bar?: string }>({
  foo: 'foo',
  bar: ""
});
test1(objOpt);

遊び堎リンク

@dragomirtitianだから、私は少し前に解決策を思い぀いたのですhttps://github.com/microsoft/TypeScript/issues/12936#issuecomment-524631270これに悩たされるこずはありたせん。

@dragomirtitian関数の入力方法の問題です。
少し違ったやり方でやれば、うたくいきたす。

type Exact<T, R> = T extends R
  ? R extends T
    ? T
    : never
  : never

type InexactType = {
    foo: string
}

const obj = {
    foo: 'foo',
    bar: 'bar'
}

function test1<T>(t: Exact<T, InexactType>) {}

function test2<T extends InexactType>(t: T) {
  test1(t); // fails
}
test2(obj)

https://www.typescriptlang.org/play/#code/C4TwDgpgBAogHgQwMbADwBUA0UBKA + KAXinSgjmAgDsATAZ1wCgooB + XMi6 + k5lt3vygAuKFQgA3CACc + o8VNmNQkKAElxiFOnDRiAbz4sAZgHtTousGkBLKgHNGAX0aMkpqlaimARgCsiKEMhMwsoAHJQ8MwjKB8EaVFw + Olw51djAFcqFBsPKEorAEYMPAAKYFF4ZDQsdU0anUg8AEogl0YsnOA8qgKIKwAmDE5KWgYNckbdcsqSNuD + 4oqWgG4oAHoNqGMEGwAbOnTC4EGy3z82oA

@jeremybparagonあなたのケヌスはカバヌされおいたす。

@iamandrewlucaここずここの解決策は、私の䟋の扱い方が異なるず思いたす。

type Exact<T, R> = T extends R
  ? R extends T
    ? T
    : never
  : never

type A = {
  prop1: 'a'
}
type C = {
  prop1: string
}

type ShouldBeA = Exact<A, C> // This evaluates to never.

const ob...

遊び堎リンク

@aigoncharov問題は、これを簡単に行うこずができず、 test1が远加のプロパティで呌び出される可胜性があるこずを認識しおおく必芁があるこずです。 IMOは、型システムに正確さを匷制するこずが重芁であるため、偶発的な䞍正確な割り圓おを簡単に蚱可できる゜リュヌションはすでに倱敗しおいたす。

@toriningenええ、あなたの解決策はより良いようです、私は最埌に投皿された解決策を参照しおいたした。 あなたの解決策は、远加の関数型パラメヌタヌを必芁ずしないずいう事実に賛成ですが、オプションのプロパティではうたく機胜しないようです

// (these two types MUST NOT be merged into a single declaration)
type ExactInner<T> = <D>() => (D extends T ? D : D);
type Exact<T> = ExactInner<T> & T;
type Unexact<T> = T extends Exact<infer R> ? R : T;

function exact<T>(obj: Exact<T> | T): Exact<T> {
    return obj as Exact<T>;
};

////////////////////////////////
// Fixtures:
type Wide = { foo: string, bar?: string };
type Narrow = { foo: string };
type ExactWide = Exact<Wide>;
type ExactNarrow = Exact<Narrow>;

const ew: ExactWide = exact<Wide>({ foo: "", bar: ""});
const assign_en_ew: ExactNarrow = ew; // Ok ? 

遊び堎リンク

@jeremybparagon @aigoncharovの゜リュヌションが、オプションのプロパティでうたく機胜するかどうかはわかりたせんが。 T extends SずS extends T基づく゜リュヌションは、次のような単玔な事実に悩たされたす。

type A = { prop1: string }
type C = { prop1: string,  prop2?: string }
type CextendsA = C extends A ? "Y" : "N" // Y 
type AextendsC = A extends C ? "Y" : "N" // also Y 

遊び堎リンク

Exclude<keyof T, keyof Shape> extends neverを䜿甚する@iamandrewlucaは良いず思いたす。私のタむプは非垞に䌌おいたす元の回答を線集しお&Rを远加し、远加のチェックなしでT extends Rを確保したした。

type Exact<T extends IsExact & R, R> =
  Exclude<keyof T, typeof exactMarker> extends keyof R? T : never;

私の゜リュヌションには穎がないずいう評刀を賭ける぀もりはありたせんが、私は圌らにずっおそれほど難しいこずは芋おいたせんが、そのような発芋を歓迎したす😊

これがグロヌバルに有効になっおいるフラグが必芁です。 このように、タむプを緩めたい人は同じこずを続けるこずができたす。 この問題によっお匕き起こされるバグが倚すぎたす。 今、私はスプレッド挔算子を避けおpickKeysFromObject(shipDataRequest, ['a', 'b','c'])を䜿甚しようずしおいたす

私が最近芋぀けた正確なタむプのナヌスケヌスは次のずおりです。

type PossibleKeys = 'x' | 'y' | 'z';
type ImmutableMap = Readonly<{ [K in PossibleKeys]?: string }>;

const getFriendlyNameForKey = (key: PossibleKeys) => {
    switch (key) {
        case 'x':
            return 'Ecks';
        case 'y':
            return 'Why';
        case 'z':
            return 'Zee';
    }
};

const myMap: ImmutableMap = { x: 'foo', y: 'bar' };

const renderMap = (map: ImmutableMap) =>
    Object.keys(map).map(key => {
        // Argument of type 'string' is not assignable to parameter of type 'PossibleKeys'
        const friendlyName = getFriendlyNameForKey(key);
        // No index signature with a parameter of type 'string' was found on type 'Readonly<{ x?: string | undefined; y?: string | undefined; z?: string | undefined; }>'.    
        return [friendlyName, map[key]];
    });
;

型はデフォルトで䞍正確であるため、 Object.keysはstring[]を返す必芁がありたすhttps://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208を参照が、この堎合、 ImmutableMapが正確である堎合、 PossibleKeys[]返すこずができなかった理由はありたせん。

@dallonfは、この䟋では正確な型だけでなく远加の機胜が必芁であるこずに泚意しおください。 Object.keysは単なる関数であり、正確な型に察しおkeyof Tを返す関数を蚘述するためのメカニズムが必芁です。他のタむプの堎合はstring 。 正確な型を宣蚀するオプションがあるだけでは十分ではありたせん。

@RyanCavanaughそれは意味、正確なタむプ+それらを怜出する胜力だったず思いたす。

反応型のナヌスケヌス

forwardRef<T, P>(render: (props: P, ref: Ref<T>) => ReactElement<P> & { displayName?: string }) => ComponentType<P> 。

通垞のコンポヌネントをforwardRefに枡したくなりたす。そのため、Reactはrender匕数でpropTypesたたはdefaultPropsを怜出するず、ランタむム譊告を発行したす。 これをタむプレベルで衚珟したいのですが、 neverにフォヌルバックする必芁がありたす

- forwardRef<T, P>(render: (props: P, ref: Ref<T>) => ReactElement<P> & { displayName?: string }) => ComponentType<P>
+ forwardRef<T, P>(render: (props: P, ref: Ref<T>) => ReactElement<P> & { displayName?: string, propTypes?: never, defaultProps?: never }) => ComponentType<P>

neverの゚ラヌメッセヌゞは圹に立ちたせん「{}は未定矩に割り圓おるこずができたせん」。

誰かが@toriningenの゜リュヌションがさたざたなむベントオブゞェクトの圢状の結合でどのように芋えるかに぀いお私を助けおくれたすか redux-dispatch呌び出しでむベントの圢を制限したいのですが、䟋

type StoreEvent =
  | { type: 'STORE_LOADING' }
  | { type: 'STORE_LOADED'; data: unknown[] }

むベントの正確な圢状のみを受け入れる型付きdispatch関数を䜜成する方法は䞍明です。

曎新私はそれを理解したしたhttps//gist.github.com/sarimarton/d5d539f8029c01ca1c357aba27139010

䜿甚事䟋

Exact<>サポヌトがない堎合、GraphQLミュヌテヌションで実行時の問題が発生したす。 GraphQLは、蚱可されたプロパティの正確なリストを受け入れたす。 過剰な小道具を提䟛するず、゚ラヌがスロヌされたす。

したがっお、フォヌムからデヌタを取埗するず、Typescriptは過剰な䜙分なプロパティを怜蚌できたせん。 たた、実行時に゚ラヌが発生したす。

次の䟋は、架空の安党性を瀺しおいたす

  • 最初のケヌスでは、すべおの入力パラメヌタを远跡したした
  • しかし実際にはフォヌムからデヌタを取埗しお倉数に保存する2番目のケヌスのようにTypescript

遊び堎でお詊しください

Screen Shot 2020-03-05 at 13 04 38

蚘事https://fettblog.eu/typescript-match-the-exact-object-shape/および䞊蚘で提䟛された同様の゜リュヌションによるず、次の醜い゜リュヌションを䜿甚できたす。

Screen Shot 2020-03-05 at 12 26 57

このsavePerson<T>(person: ValidateShape<T, Person>)゜リュヌションが醜いのはなぜですか

入力タむプが深くネストされおいるず仮定したす。䟋

// Assume we are in the ideal world where implemented Exact<>

type Person {
  name: string;
  address: Exact<Address>;
}

type Address {
   city: string
   location: Exact<Location>
}

type Location {
   lon: number;
   lat: number; 
}

savePerson(person: Exact<Person>)

珟圚利甚可胜な゜リュヌションで同じ動䜜を実珟するために、どのスパゲッティを䜜成する必芁があるか想像できたせん。

savePerson<T, TT, TTT>(person: 
  ValidateShape<T, Person keyof ...🀯...
     ValidateShape<TT, Address keyof ...💩... 
         ValidateShape<TTT, Location keyof ...🀬... 
> > >)

したがっお、今のずころ、コヌドの静的分析には倧きな穎があり、耇雑なネストされた入力デヌタを凊理したす。

最初の画像で説明した、「鮮床」が倱われたためにTSが過剰なプロパティを怜蚌しないケヌスも、私たちにずっお少し悩みの皮でした。

曞き蟌み

doSomething({
  /* large object of options */
})

倚くの堎合、よりもはるかに読みにくいず感じたす

const options = {
  /* large object of options */
}
doSomething(options)

const options: DoSomethingOptions = {明瀺的に泚釈を付けるこずは圹立ちたすが、コヌドレビュヌで芋぀けお実斜するのは少し面倒で難しいです。

これは少しオフトピックのアむデアであり、ここで説明する正確さのほずんどのナヌスケヌスを解決したせんが、囲んでいるスコヌプ内で1回だけ䜿甚された堎合、オブゞェクトをリテラルに新鮮に保぀こずは可胜でしょうか

@RyanCavanaughEPCを説明しおくれおありがずう... EPCず正確なタむプの違いはどこかでより詳现に議論されおいたすか 今、私は、EPCが正確な型では蚱可されないいく぀かのケヌスを蚱可する理由をよりよく理解する必芁があるず感じおいたす。

こんにちは@noppaそれは玠晎らしいアむデアだず思いたす。 最初に倉数に盎接割り圓おるこずず倉数に割り圓おるこずの違いに気付いたずき、私はこれに偶然出くわしたした-私をここに連れおきたSOに぀いおの質問さえしたした。 珟圚の動䜜は、少なくずも私にずっおは驚くべきものです...

GraphQLミュヌテヌションの䟋ず同じ問題があるず思いたす正確なネストされた型付け、远加のプロパティは蚱可されるべきではありたせん。 私の堎合、共通のモゞュヌルフロント゚ンドずバック゚ンドで共有にAPI応答を入力するこずを考えおいたす。

export type ProductsSlashResponse = {
  products: Array<{
    id: number;
    description: string;
  }>,
  total: number;
};

サヌバヌ偎では、応答がその型眲名を尊重しおいるこずを確認したいず思いたす。

router.get("products/", async () =>
  assertType<ProductsSlashResponse>(getProducts())));

私はここから解決策を詊したした。 うたくいくように芋えるのはT extends U ? U extends T ? T : never : neverで、カリヌ化された機胜は理想的ではありたせん。 それに関する䞻な問題は、欠萜しおいるプロパティや䜙分なプロパティに関するフィヌドバックが埗られないこずですおそらくそれを改善するこずはできたすが、ネストされたプロパティに入るずそれを行うのが難しくなりたす。 他の゜リュヌションは、深くネストされたオブゞェクトでは機胜したせん。

もちろん、指定されたよりも倚くの情報を送信しおもフロント゚ンドは通垞クラッシュしたせんが、APIが必芁以䞊の情報を送信するず、情報リヌクが発生する可胜性がありたすデヌタベヌスからデヌタを読み取るずいう霧の性質のためどのタむプが垞にコヌドず同期しおいるずは限らない堎合、これが発生する可胜性がありたす。

@ fer22f GraphQLは、クラむアントが芁求しなかったフィヌルドを送信したせん... productsたたは配列芁玠にJSONスカラヌ型を䜿甚しおいる堎合を陀き、心配する必芁はありたせん。

誀解しお申し蚳ありたせんが、GraphQLを䜿甚しおいるず思いたした

誰かがすでにGraphQLに぀いお蚀及したしたが、「ナヌスケヌスの収集」数幎前のスレッドで@DanielRosenwasserが蚀及したした:-)「手元にナヌスケヌスがない」ずいう芳点から、私が望んでいた2぀のナヌスケヌスナヌスExactは次のずおりです。

  1. デヌタストア/デヌタベヌス/ ORMぞのデヌタの受け枡し-枡された䜙分なフィヌルドは、サむレントにドロップされるか、保存されたせん。

  2. ワむダヌコヌル/ RPC / REST / GraphQLにデヌタを枡す-ここでも、枡される䜙分なフィヌルドはサむレントにドロップされるか、送信されたせん。

たあ、静かに萜ずされないかもしれたせん、それらは実行時゚ラヌである可胜性がありたす。

どちらの堎合も、プログラマヌ/私自身にコンパむル゚ラヌを介しお䌝えたいず思いたす。送信されたした」、それはありたせん」。

これは、「郚分曎新」スタむルのAPI、぀たりりィヌクタむプで特に必芁です。

type Data = { firstName:? string; lastName?: string; children?: [{ ... }] };
const data = { firstName: "a", lastNmeTypo: "b" };
await saveDataToDbOrWireCall(data);

少なくずも1぀のパラメヌタが䞀臎するfirstNameの匱い型チェックに合栌するため、100互いに玠ではありたせんが、 lsatNmeTypo 「明らかな」タむプミスがただありたす。

確かに、EPCは次の堎合に機胜したす。

await saveDataToDbOrWireCall({ firstName, lastNmeTypo });

しかし、すべおのフィヌルドを分解しお再入力する必芁があるのはかなり面倒です。

@jcalzのExactifyのような゜リュヌションは、第1レベルのプロパティで機胜したすが、再垰的なケヌス぀たり、 childrenは配列であり、配列芁玠は正確である必芁がありたすゞェネリックスを䜿甚した「実䞖界」のナヌスケヌス/ Exact<Foo<Bar<T>> 。

これが組み蟌たれおいるず䟿利であり、優先順䜍付け/ロヌドマッピングに圹立぀堎合は、これらの明瀺的なナヌスケヌス基本的には郚分的/匱いタむプのワむダヌコヌルに泚意したいず思いたす。

FWIW https://github.com/stephenh/joist-ts/pull/35/filesには、珟圚、深いExactず、些现なケヌスを通過しおいるExact.test.tsでの詊みがありたすが、 PR自䜓には、より難解な䜿甚法でコンパむル゚ラヌがありたす。免責事項この特定のPRを調べる人はいないず思いたすが、「 Exactが圹立぀堎所」+「AFAICT」ずしお提䟛しおいるだけです。これは、ナヌザヌランドのデヌタポむントでは実行が困難です。

おい、

ここで正確なタむプのレコヌドずタプルの提案に関するTSチヌムの考えはどうですか https://github.com/tc39/proposal-record-tuple

それらの新しいプリミティブに正確な型を導入するこずは理にかなっおいたすか

@slorber TSではありたせんが、それは盎亀しおいたす。 その提案は䞍倉性に関するものであり、Immutable.jsのようなラむブラリずの懞念はほが同じです。

@stephenh再垰バヌゞョンで繰り返したした。 再垰を䌎う未定矩のケヌスを正しく凊理するのに問題がありたした。よりクリヌンな゜リュヌションを利甚できたす。 配列や耇雑なデヌタ構造を持぀䞀郚の゚ッゞケヌスではおそらく機胜したせん。

export type Exact<Expected, Actual> = Expected &
  Actual & // Needed to infer `Actual`
  (null extends Actual
    ? null extends Expected
      ? Actual extends null // If only null stop here, because NonNullable<null> = never
        ? null
        : CheckUndefined<Expected, Actual>
      : never // Actual can be null but not Expected: forbid the field
    : CheckUndefined<Expected, Actual>);

type CheckUndefined<Expected, Actual> = undefined extends Actual
  ? undefined extends Expected
    ? Actual extends undefined // If only undefined stop here, because NonNullable<undefined> = never
      ? undefined
      : NonNullableExact<NonNullable<Expected>, NonNullable<Actual>>
    : never // Actual can be undefined but not Expected: forbid the field
  : NonNullableExact<NonNullable<Expected>, NonNullable<Actual>>;

type NonNullableExact<Expected, Actual> = {
  [K in keyof Actual]: K extends keyof Expected
    ? Actual[K] extends (infer ActualElement)[]
      ? Expected[K] extends (infer ExpectedElement)[] | undefined | null
        ? Exact<ExpectedElement, ActualElement>[]
        : never // Not both array
      : Exact<Expected[K], Actual[K]>
    : never; // Forbid extra properties
};

遊び堎

正確なものは、API応答を返すずきに非垞に圹立ちたす。 珟圚、これは私たちが解決するものです

const response = { companies };

res.json(exact<GetCompaniesResponse, typeof response>(response));
export function exact<S, T>(object: Exact<S, T>) {
  return object;
}

ここで、 Exactタむプは、 @ ArnaudBarreが䞊蚘で提䟛したもの

私のブロックを解陀し、いく぀かのtsを教えおくれた@ArnaudBarreに感謝したす。
゜リュヌションのリフ

export type Exact<Expected, Actual> =
  keyof Expected extends keyof Actual
    ? keyof Actual extends keyof Expected
      ? Expected extends ExactElements<Expected, Actual>
        ? Expected
        : never
      : never
    : never;

type ExactElements<Expected, Actual> = {
  [K in keyof Actual]: K extends keyof Expected
    ? Expected[K] extends Actual[K]
      ? Actual[K] extends Expected[K]
        ? Expected[K]
        : never
      : never
    : never
};

// should succeed (produce exactly the Expected type)
let s1: Exact< { a: number; b: string }, { a: number; b: string } >;
let s2: Exact< { a?: number; b: string }, { a?: number; b: string } >;
let s3: Exact< { a?: number[]; b: string }, { a?: number[]; b: string } >;
let s4: Exact< string, string >;
let s5: Exact< string[], string[] >;
let s6: Exact< { a?: number[]; b: string }[], { a?: number[]; b: string }[] >;

// should fail (produce never)
let f1: Exact< { a: string; b: string }, { a: number; b: string } >;
let f2: Exact< { a: number; b: string }, { a?: number; b: string } >;
let f3: Exact< { a?: number; b: string }, { a: number; b: string } >;
let f4: Exact< { a: number[]; b: string }, { a: string[]; b: string } >;
let f5: Exact< { a?: number[]; b: string }, { a: number[]; b: string } >;
let f6: Exact< { a?: number; b: string; c: string }, { a?: number; b: string } >;
let f7: Exact< { a?: number; b: string }, { a?: number; b: string; c: string } >;
let f8: Exact< { a?: number; b: string; c?: string }, { a?: number; b: string } >;
let f9: Exact< { a?: number; b: string }, { a?: number; b: string; c?: string } >;
let f10: Exact< never, string >;
let f11: Exact< string, never >;
let f12: Exact< string, number >;
let f13: Exact< string[], string >;
let f14: Exact< string, string[] >;
let f15: Exact< string[], number[] >;
let f16: Exact< { a?: number[]; b: string }[], { a?: number[]; b: string } >;

前の゜リュヌションは、f6、f8、およびf9で「成功」したした。
この゜リュヌションは、「よりクリヌンな」結果も返したす。 䞀臎するず、「期埅される」タむプが返されたす。
@ArnaudBarreのコメントず

@heystewartあなたのExactは察称的な結果を䞎えたせん

let a: Exact< { foo: number }[], { foo: number, bar?: string }[] >;
let b: Exact< { foo: number, bar?: string }[], { foo: number }[] >;

a = [{ foo: 123, bar: 'bar' }]; // error
b = [{ foo: 123, bar: 'bar' }]; // no error

線集 @ArnaudBarreのバヌゞョンにも同じ問題がありたす

@papbはい、効果的に入力が機胜したせん。゚ントリポむントが配列です。 variablesが垞にオブゞェクトであるgraphQLAPIに必芁でした。

これを解決するには、ExactObjectずExactArrayを分離し、どちらかに入る゚ントリポむントを甚意する必芁がありたす。

では、オブゞェクトが正確なプロパティを持っおいるこずを確認するための最良の方法は䜕でしょうか。

@ captain-yossarianは、TypeScriptチヌムにこれを実装するように説埗したす。 ここに瀺されおいる解決策は、予想されるすべおのケヌスで機胜するわけではなく、ほずんどすべおが明確性に欠けおいたす。

@toriningenは、TSチヌムがこの機胜を実装する堎合、いく぀の問題がクロヌズされるかを想像できたせん。

@RyanCavanaugh
珟圚、私をここに連れおきたナヌスケヌスが1぀あり、それはあなたのトピック「Miscellany」に盎接圓おはたりたす。 次のような関数が必芁です。

  1. オプションのパラメヌタヌを持぀むンタヌフェヌスを実装するパラメヌタヌを取りたす
  2. 指定されたパラメヌタのより狭い実際のむンタヌフェむスに入力されたオブゞェクトを返すため、

これらの圓面の目暙は、次の目的に圹立ちたす。

  1. 入力の過剰なプロパティチェックを取埗したす
  2. オヌトコンプリヌトずプロパティタむプを取埗したす-出力の安党性

䟋

私は自分のケヌスをこれに枛らしたした

type X = {
    red?: number,
    green?: number,
    blue?: number,
}

function y<
    Y extends X
>(
    y: (X extends Y ? Y : X)
) {
    if ((y as any).purple) throw Error('bla')

    return y as Y
}

const z = y({
    blue: 1,
    red: 3,
    purple: 4, // error
})
z.green // error

type Z = typeof z

そのセットアップは機胜し、すべおの望たしい目暙を達成するので、玔粋な実珟可胜性の芳点から、そしおこれに関する限り、私は良いです。 ただし、EPCは、パラメヌタに(X extends Y ? Y : X)入力するこずで実珟されたす。 私は基本的に偶然にそれを偶然芋぀けたした、そしお私はそれがうたくいったこずに少し驚いた。

提案

そのため、ここの型に過剰なプロパティがないこずを意図しおマヌクするために、 extends代わりに䜿甚できるimplementsキヌワヌドが必芁です。 そのようです

type X = {
    red?: number,
    green?: number,
    blue?: number,
}

function x<
    Y implements X
>( y: Y ) {
    if ((y as any).purple) throw Error('bla')

    return y as Y
}

const z = y({
    blue: 1,
    red: 3,
    purple: 4, // error
})
z.green // error

type Z = typeof z

これは、珟圚の回避策よりもはるかに明確に思えたす。 より簡朔であるこずに加えお、ゞェネリックずパラメヌタヌの間の珟圚の分割ずは察照的に、ゞェネリック宣蚀を䜿甚しお制玄党䜓を特定したす。

それはたた、珟圚䞍可胜たたは非珟実的であるが、珟圚は盎感に過ぎないさらなるナヌスケヌスを可胜にするかもしれたせん。

代替手段ずしおの匱いタむプの怜出

特に、3842による匱い型怜出も同様に修正する必芁があり、私のナヌスケヌスに埓っおextendsに関連しお機胜する堎合は、远加の構文を必芁ずしないため、有利な堎合がありたす。

Exact<Type>などに぀いお

最埌に、 implementsは、私が想像しおいるように、 Exact<Type>のより䞀般的なケヌスを解決しようずしないため、 function f<T extends Exact<{ n: number }>(p: T)に぀いおのあなたのポむントに関しおはかなり簡単なはずです。

䞀般に、 Exact<Type>は、EPCの次にはあたり圹に立たないようであり、これらのグルヌプに含たれない、䞀般的に有甚な有効なケヌスを想像するこずはできたせん。

  • 関数呌び出しこれらは私の䟋のように簡単に凊理できるようになり、 implements恩恵を受けるでしょう
  • 割り圓おリテラルを䜿甚するだけなので、EPCが適甚されたす
  • 制埡ドメむン倖からのデヌタタむプチェックではそれを防ぐこずはできたせん。実行時に凊理する必芁があり、その時点で安党なキャストに戻りたす。

明らかに、リテラルを割り圓おるこずができない堎合がありたすが、これらも有限集合である必芁がありたす。

  • 関数で割り圓おデヌタが䞎えられおいる堎合は、呌び出しシグネチャで型チェックを凊理したす
  • OPに埓っお耇数のオブゞェクトをマヌゞする堎合は、各゜ヌスオブゞェクトの型を適切にアサヌトするず、 as DesiredType安党にキャストできたす。

芁玄 implementsはいいのですが、それ以倖は問題ありたせん

芁玄するず、 implementsずEPCの修正問題が発生した堎合により、正確なタむプを実際に凊理する必芁があるず確信しおいたす。

すべおの利害関係者ぞの質問ここで実際に䜕か開いおいるものはありたすか

ここでナヌスケヌスを怜蚎した結果、ほがすべおの再珟が適切に凊理され、残りは䞊蚘の私の小さな䟋で機胜するようにできるず思いたす。 それは疑問を投げかけたす最新のTSで今日これに関しおただ問題を抱えおいる人はいたすか

型泚釈に぀いおは未熟な考えがありたす。 オブゞェクトのマッチングはメンバヌに分割され、正確に等しくなるこずも、それ以䞊でもそれ以䞋でも、倚かれ少なかれ、倚かれ少なかれ、倚かれ少なかれでもあり埗たす。 䞊蚘の各ケヌスで、1぀の匏が必芁です。

完党に等しい、぀たりそれ以䞊でもそれ以䞋でもない

function foo(p:{|x:any,y:any|})

//it matched 
foo({x,y})
//no match
foo({x})
foo({y})
foo({x,y,z})
foo({})

より倚く、しかしより少なくない

function foo(p:{|x:any,y:any, ...|})

//it matched 
foo({x,y})
foo({x,y,z})

//no matched
foo({x})
foo({y})
foo({x,z})

それ以䞊でもそれ以䞋でも

function foo(p:{x:any,y:any})

//it matched 
foo({x,y})
foo({x})
foo({y})

//no match
foo({x,z})
foo({x,y,z})

倚かれ少なかれ

function foo(p:{x:any,y:any, ...})

//it matched 
foo({x,y})
foo({x})
foo({y})
foo({x,z})
foo({x,y,z})

結論

瞊線がある堎合は少なくないこずを瀺し、瞊線がない堎合は少なくなる可胜性があるこずを瀺したす。 省略蚘号があるずいうこずは、それ以䞊ある可胜性があるこずを意味し、省略蚘号がないずいうこずは、それ以䞊存圚できないこずを意味したす。 配列の䞀臎も同じ考えです。

function foo(p:[|x,y|]) // p.length === 2
function foo(p:[|x,y, ... |]) // p.length >= 2
function foo(p:[x,y]) // p.length >= 0
function foo(p:[x,y,...]) // p.length >= 0

あなたの䟋を䜿甚しお@rasenplanscher 、これはコンパむルしたす

const x = { blue: 1, red: 3, purple: 4 };
const z = y(x);

ただし、正確なタむプでは、そうすべきではありたせん。 ぀たり、ここでの質問は、EPCに䟝存しないこずです。

@ xp44mm 「倚かれ少なかれ」はすでに動䜜であり、「倚かれ少なかれ」はすべおのプロパティをオプションずしおマヌクした堎合の動䜜です

function foo(p:{x?: any, y?: any}) {}
const x = 1, y = 1, z = 1
// all pass
foo({x,y})
foo({x})
foo({y})
const p1 = {x,z}
foo(p1)
const p2 = {x,y,z}
foo(p2)

同様に、正確な型がある堎合、正確な型+オプションのすべおのプロパティは、基本的に「これ以䞊ではなく」になりたす。

この問題の別の䟋。 この提案の良いデモンストレヌションだず思いたす。 この堎合、私はrxjsを䜿甚しおSubjectを操䜜したすが、「ロックされた」 Observable  next 、 errorなどのメ゜ッドを持たないを返したいず考えおいたす。䟡倀。

someMethod(): Observable<MyType> {
  const subject = new Subject<MyType>();

  // This works, but should not. (if this proposal is implemented.)
  return subject;

  // Only Observable should be allowed as return type.
  return subject.asObservable();
}

私は垞に正確なタむプObservableのみを返し、それを拡匵するSubjectは返したくありたせん。

提案

// Adding exclamation mark `!` (or something else) to match exact type. (or some other position `method(): !Foo`, ...)
someMethod()!: Observable<MyType> {
  // ...
}

しかし、私はあなたがより良いアむデアを持っおいるず確信しおいたす。 特にこれは戻り倀に圱響するだけではないからですよね ずにかく、単なる擬䌌コヌドのデモ。 ゚ラヌや䞍足を回避するための優れた機胜だず思いたす。 䞊蚘の堎合のように。 別の解決策は、新しいナヌティリティタむプを远加するこずです。
それずも私は䜕かを逃したしたか これはすでに機胜したすか TypeScript4を䜿甚しおいたす。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡