ããã¯ãæ£ç¢ºãªåã®æ§æãæå¹ã«ããããã®ææ¡ã§ãã åæ§ã®æ©èœã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ã§èšåãããŠããæšå¥šæ§æææ¡ã䜿çšããããã«æŽæ°ãããŸãããããã«ã¯ãåŒã§ã®äœ¿çšãå¯èœã«ããããã®ãžã§ããªãã¯åã§ã®ããåçŽãªæ§æã®äœ¿çšãå«ãŸããŸãã
ããã§æ§æã«ã€ããŠè°è«ã®äœå°ãããããšããå§ãããŸãã 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ã€ã®è©Šè¡ã®å°ãäžèªç¶ãªäŸã§ãã
CorrectObject
ã«é¢ããŠéå°ãªããããã£ã¯ãããŸãã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ã¯ãããªãã瀺ããã®ãšåãã¿ã€ãã®ã¬ãã¥ãŒãµãŒé¢æ°ã§ããã確å®ã«èŠã€ããŸããã
ããªããæã£ãŠãããã®ããããã€ãã®è¿œå ã®ãªãã·ã§ã³ïŒ
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
};
}
interface State {
name: string;
}
function nameReducer(state: State, action: Action<string>) {
return (state = {
...state,
fullName: action.payload // THIS IS REPORTED AS AN ERROR
});
}
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;
}
...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
ãã¡ãããã¿ã€ããã¹ã®ããã«ããã倱æããããšãæåŸ ããŸã-ãã®ããããã£ã¯äž¡æ¹ã§ãªãã·ã§ã³ã§ããã
ããã§ãç§ã¯ããªãç§ãã¡ã¯ããããããã欲ããã®ã§ããïŒãã«æ»ããŸãã
ç§ã¯ããããããã®çç±ïŒãŸãã¯ç¶æ³ã«å¿ããŠãµãã»ããïŒã®ããã ãšæããŸãïŒ
ãæ£ç¢ºãªãªãã·ã§ã³ã®ããããã£ããé©åã«åŠçãããªãå Žåããããã®å©ç¹ã®ããã€ãã¯å£ããŠããããéåžžã«æ··ä¹±ããŠããŸãïŒ
ãŸããäžèšã®äŸã§ã¯ãã¿ã€ããã¹ãåé¿ããããã«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 ããã以äžã®ãã®ã¯ãªããããªã¢ã³ãã§
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 }
ã¯é©åã§ã¯ãããŸããã æ£ç¢ºãªã¿ã€ãããå²ãåœãŠãå Žåããã®ã«ãŒã«ã¯é©åã«ãªããŸãã å®éã«ã¯ãç§ã¯ãã®ã«ãŒã«ã䜿çšããŸããã ããããæ£ç¢ºãªã¿ã€ããæããªãã¬ã¬ã·ãŒã·ã¹ãã ã«é©ããŠããããã§ãã
ç§ã¯ãå°éå ·ã®ééãæ¹åããæ£ç¢ºãªã¿ã€ããšãã¹ãã¬ããã¿ã€ãã®ç°¡çŽ åã«ç§ã®æåŸã®åžæãåºå®ããŸããã çŸå®ã«ã¯ãæ£ç¢ºãªåã¯æçããªã¢ãŒãã£ãºã ã®ã¢ã³ãããŒãŒã§ãããåºæ¬çã«éæ§æçã§ãã
æçãžã§ããªãã¯ã䜿çšãããšãæ°ã«ãªãå°éå ·ãæå®ããæ®ããééãããããšãã§ããŸãã å¢çãæ£ç¢ºã«ãªããšããã«ãå¹ ã®ãµãã¿ã€ããå®å šã«å€±ããããžã§ããªãã¯ã®æçšæ§ãå€§å¹ ã«äœäžããŸãã ãã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éé
åžã¿ã€ãã¯ã»ãšãã©å¿
èŠãããŸããã
æ§ææäœã§ãããããé åžã®åŒ·åãªçè«çæ ¹æ ã¯ãããŸããã
çŸå®ã«ã¯ãããã¯éåžžã«äŸ¿å©ã§ãããä»ã®æ¹æ³ã§ãšã³ã³ãŒãããããšãããšèŠçã«ãªããŸãã
çŸç¶ã§ã¯ãäŒè©±ããããã¯ããé ãããåã«ãå ã«é²ãã§ç«ã¡å»ããŸãã
åæ£æ§ã«ã€ããŠã¯ãã§ã«å€ãã®åé¡ããããŸãããæ°ããæ§æãå¿ èŠã«ãªãããšã«çŽé¢ããªãã®ã¯ãªãã§ããïŒ
åé¡ã®äŸã次ã«ç€ºããŸãã
ãŠãŒã¶ãŒ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
ãšã©ãŒã®è©³çŽ°
ããã§ã®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ã€ã®ãšã©ãŒãçºçãããšäºæ³ãããŸãã
éã³å Ž
@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
ãžã®åŒã³åºãã§ããªãã®äŸ¡å€ãå
ãå¿
èŠãªãã«ãããæ©èœãããæ¹æ³ãèŠã€ããããšãã§ããã°ãããã¯å®ç§ã§ãããã
ãããæ£ããåé¡ãã©ããã¯ããããŸãããããããç§ãåãããããšã®äŸã§ãã
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ã¯éå°ãªïŒäœåãªïŒããããã£ãæ€èšŒã§ããŸããã ãŸããå®è¡æã«ãšã©ãŒãçºçããŸãã
次ã®äŸã¯ãæ¶ç©ºã®å®å šæ§ã瀺ããŠããŸã
éã³å Žã§ãè©Šããã ãã
èšäºhttps://fettblog.eu/typescript-match-the-exact-object-shape/ããã³äžèšã§æäŸãããåæ§ã®ãœãªã¥ãŒã·ã§ã³ã«ãããšã次ã®éããœãªã¥ãŒã·ã§ã³ã䜿çšã§ããŸãã
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
ã¯æ¬¡ã®ãšããã§ãã
ããŒã¿ã¹ãã¢/ããŒã¿ããŒã¹/ ORMãžã®ããŒã¿ã®åãæž¡ã-æž¡ãããäœåãªãã£ãŒã«ãã¯ããµã€ã¬ã³ãã«ãããããããããä¿åãããŸããã
ã¯ã€ã€ãŒã³ãŒã«/ 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ãã«çŽæ¥åœãŠã¯ãŸããŸãã 次ã®ãããªé¢æ°ãå¿
èŠã§ãã
ãããã®åœé¢ã®ç®æšã¯ã次ã®ç®çã«åœ¹ç«ã¡ãŸãã
ç§ã¯èªåã®ã±ãŒã¹ãããã«æžãããŸããïŒ
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
æ©æµãåããã§ãããæããã«ããªãã©ã«ãå²ãåœãŠãããšãã§ããªãå ŽåããããŸãããããããæééåã§ããå¿ èŠããããŸãã
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ã䜿çšããŠããŸãã
æãåèã«ãªãã³ã¡ã³ã
ç§ãã¡ã¯ããã«ã€ããŠããªãé·ãé話ããŸããã è°è«ãèŠçŽããããšæããŸãã
éå°ãªããããã£ãã§ãã¯
æ£ç¢ºãªã¿ã€ãã¯ãè¿œå ã®ããããã£ãæ€åºããããã®åãªãæ¹æ³ã§ãã æåã«éå°ããããã£ãã§ãã¯ïŒ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ã䜿çšããŠãäžè¯ãããããã£ãæ€åºããå¿ èŠããããŸãã ãããã£ãŠãåé¡ããããæ£ç¢ºãªã¿ã€ããæ£ãã解決çã§ãããšæãããå Žåã¯ãããã§å ã®åé¡ã説æããŠãã ããããã¿ãŒã³ã®ã«ã¿ãã°ãäœæãã䟵襲æ§ãæ··ä¹±ãå°ãªãä»ã®è§£æ±ºçããããã©ããã確èªã§ããŸãã