ìŽê²ì ì íí ì íì ëí 구묞ì íì±ííêž° ìí ì ìì ëë€. 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 ê°ì¬í©ëë€. ëŽ ìŽêž° 묞ì ë ê·žê²ì ìžêžíì§ë§ ëêµ°ê°ê° ìŽìšë ë ëì 구묞ì ê°ì§ ê²ìŽêž° ë묞ì ê²°êµ ìëµíìµëë€.
@DanielRosenwass íšì¬ ë í©ëŠ¬ì ìŒë¡ 볎ì ëë€. ê°ì¬í©ëë€!
@wallverb ëë ê·žë ê² ìê°íì§ ìì§ë§, ê·ž êž°ë¥ìŽ ì¡Žì¬íë ê²ë ë³Žê³ ì¶ìµëë€ ð
ìŒë¶ë ì ííê³ ìŒë¶ë ì ííì§ ìì ì íì í©ì§í©ì íííë €ë©Ž ìŽë»ê² íŽìŒ í©ëê¹? ì ìë 구묞ì 공백ì ëíŽ í¹ë³í 죌ì륌 êž°ìžìŽëëŒë ì€ë¥ê° ë°ìíêž° ìœê³ ìœêž° ìŽë µê² ë§ëëë€.
|Type1| | |Type2| | Type3 | |Type4| | Type5 | |Type6|
ë žë ì¡°í©ì ìŽë€ 구ì±ììŽ ì ííì§ ììì§ ë¹šëŠ¬ ì ì ììµëê¹?
ê·žëŠ¬ê³ ì¡°ì¬ì€ëœê² ê°ê²©ì ëì§ ììŒë©Ž?
|Type1|||Type2||Type3||Type4||Type5||Type6|
(ëµë³: Type3
, Type5
)
@rotemdan ìì ëµë³ì ì°žì¡°íììì€. ëì ì ë€ëŠ ì í Extact
ìŽ ììµëë€. ìŽë ì ê²ë³Žë€ ë ê²¬ê³ í ì ìì
ëë€. ìŽê²ìŽ ì ížëë ì ê·Œ ë°©ììŽëŒê³ ìê°í©ëë€.
ížì§êž° ííž, 믞늬볎Ʞ íì ë° ì»ŽíìŒë¬ ë©ìì§ìì ìŽë»ê² 볎ìŒì§ì ëí ì°ë €ë ììµëë€. ì í ë³ì¹ì íì¬ ìì ì í ííììŒë¡ "ííí"í©ëë€. ë³ì¹ì 볎졎ëì§ ììŒë¯ë¡ ìŽì ëìíêž° ìíŽ ëª ê°ì§ í¹ë³í ì¡°ì¹ê° ì ì©ëì§ ìë í ìŽíŽí ì ìë ííìŽ ížì§êž°ì ê³ì ëíë©ëë€.
Typescriptì ëìŒí 구묞ì ì¬ì©íë ê³µì©ì²Žë¥Œ ê°ê³ ìë Flowì ê°ì íë¡ê·žëë° ìžìŽì ìŽ êµ¬ë¬žìŽ ìì©ëìë€ë ê²ìŽ ë¯¿êž°ì§ ììµëë€. ëìê² êž°ì¡Ž 구묞곌 귌볞ì ìŒë¡ 충ëíë ê²°íš ìë 구묞ì ëì í ë€ì ê·žê²ì "ë®êž°" ìíŽ ë§€ì° ìŽì¬í ë žë ¥íë ê²ì íëª íì§ ìì ê² ê°ìµëë€.
í¥ë¯žë¡ìŽ (ì¬ë¯žìë?) ëì ì€ íëë only
ì ê°ì ìì ì륌 ì¬ì©íë ê²ì
ëë€. ëª ë¬ ì ì ìŽì ëí ì ì ìŽììŽ ììë ê² ê°ìë° ì ì¶í ì ìŽ ììµëë€.
function test(a: only string, b: only User) {};
ê·žê²ì ë¹ì ëŽê° ì°Ÿì ì ìë ìµê³ ì 구묞ìŽììµëë€.
_Edit_: just
ë ìëí ê¹ì?
function test(a: just string, b: just User) {};
_(ížì§: ìŽì êµ¬ë¬žìŽ ìë ëª ëª© ì íì ëí ìì ì륌 ìí ê²ìŽì§ë§ ì€ì ë¡ë ì€ìíì§ ìì ê² ê°ìµëë€. ë ê°ë ì 충ë¶í ê°ê¹êž° ë묞ì ìŽ í€ìëë ì¬êž°ìì ìëí ì ììµëë€)_
ë í€ìë 몚ë ìœê° ë€ë¥ž ë ê°ì§ ì íì ìŒì¹ë¥Œ ì€ëª íêž° ìíŽ ëì ë ì ìëì§ ê¶êží©ëë€.
just T
(ì믞: "ì íí T
")ë ì¬êž°ì ì€ëª
ë ëë¡ ì íí 구조ì ìŒì¹ë¥Œ ìí ê²ì
ëë€.only T
(ì믞: "ê³ ì íê² T
") ëª
목 ìŒì¹.ëª ëª©ì ìŒì¹ë ì íí 구조 ìŒì¹ì "ë ì격í" ë²ì ìŒë¡ 볌 ì ììµëë€. ìŽë ì íìŽ êµ¬ì¡°ì ìŒë¡ ëìŒíŽìŒ í ë¿ë§ ìëëŒ ê° ìì²Žê° ì§ì ë ê²ê³Œ ì íí ëìŒí ì í ìë³ìì ì°êŽëìŽìŒ íšì ì믞í©ëë€. ìŽê²ì ìží°íìŽì€ ë° íŽëì€ ìžìë ì í ë³ì¹ì ì§ìíê±°ë ì§ìíì§ ìì ì ììµëë€.
only
ì ê°ì ëª
목 ìììŽì ê°ë
ìŽ ì ì íì§ íëšíë ê²ì Typescript íì 몫ìŽëŒê³ ìê°íì§ë§ ê°ìžì ìŒë¡ 믞ë¬í ì°šìŽê° ê·žë ê² ë§ì íŒëì ìŒêž°í ê²ìŽëŒê³ ìê°íì§ ììµëë€. ëë ìŽê²ì ìµì
ìŒë¡ ì ìí ë¿ì
ëë€.
_(ížì§: íŽëì€ì íšê» ì¬ì©í ë only
ì ëí ì°žê³ ì¬í: Ʞ볞 íŽëì€ê° ì°žì¡°ë ë ëª
목 íì íŽëì€ë¥Œ íì©í ì§ ì¬ë¶ì ëí 몚ížì±ìŽ ììµëë€. ìŽë ë³ëë¡ ë
ŒìíŽìŒ í©ëë€. ë®ì ì ë - ìží°íìŽì€ì ëíŽìë ëìŒíê² ê³ ë €í ì ìì - íì¬ë¡ìë ê·žë ê² ì ì©í ê²ìŽëŒê³ ìê°íì§ ìì§ë§)_
ìŽê²ì ìŒì¢ ì ë³ì¥ë ëºì ì íì²ëŒ 볎ì ëë€. ë€ì 묞ì ë êŽë šìŽ ìì ì ììµëë€. https://github.com/Microsoft/TypeScript/issues/4183 https://github.com/Microsoft/TypeScript/issues/7993
@thanresnick 귞걞 ì 믿ëì?
ìŽê²ì ëŽê° ì§êž ìì íê³ ìë ìœëë² ìŽì€ìì ë§€ì° ì ì©í ê²ì ëë€. ìŽê²ìŽ ìŽë¯ž ìžìŽì ìŒë¶ìë€ë©Ž ì€ë ì€ë¥ë¥Œ ì¶ì íë ë° ìê°ì ì°ì§ ììì ê²ì ëë€.
(ë€ë¥ž ì€ë¥ìŒ ìë ìì§ë§ ìŽ í¹ì ì€ë¥ë ìëëë€ ð)
ëë 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ì ëí ë€ížìí¬ ížì¶ ëë ë°ìŽí°ë² ìŽì€ìì ìëíë ìì ì ë§€ì° ì ì©í©ëë€.
@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
).
ë¶ëª
í "ì¶ê° ë°ìŽí°ê° 죌ìŽì§ë©Ž throw" íšìë ì íí ì íì íì©íë ê²ìŒë¡ íìëìŽìŒ í©ëë€. ê·žë¬ë ì€ê°ì ìŽë»ìµëê¹? ì¬ëë€ì ìë§ ëìíì§ ìì ê²ì
ëë€. 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)
ì(ë) ë¬Žìš ë»ìžê°ì? :íŒëì€ë¬ìŽ:
ì¢
ì¢
ë¹ì ìŽ ì ë§ë¡ ìíë ê²ìŽ "ìë ë¶ëŠ¬ë(auto-disjointed)" í©ì§í©ìž ê²œì° ì íí ì íìŽ ì구ë©ëë€. ìŠ, { 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 ì°ì°ìì ëìì 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>
ì¢íë©Ž ìì íì§ ìê² ì£ ?
ë€ì ì륌 ê³ ë €íììì€.
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
í ë¹í ì ììµëë€.
@ë€ë£šëªš
ììœìì ì§ì íë¯ìŽ ëŽ ë¬žì ë ì íí ìží°íìŽì€ê° íìíë€ë ê²ìŽ ìëëŒ ì ííê² ìëíë €ë©Ž ì€íë ë ì°ì°ìê° íìíë€ë ê²ì ëë€. ê·žë¬ë 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 ë§ìµëë€. ì룚ì
ì ì ìëì§ ìì ê²ì íì©íì§ë§ ì êŽì ììë ìŽê²ìŽ íì©ë©ëë€. ì ì룚ì
ìì íìŽë¡ëì íìí 맀ê°ë³ìê° ìë ìì
ìì±ìë§ ì¬ì©íê³ ìêž° ë묞ì
ëë€. ìŽë ê² íë©Ž ì ìëì§ ìì ê°ìŽ ì ë ììŽìŒ í©ëë€. nullableìŽ ìë ìì±ì í ë¹ë©ëë€.
ì€ì ë¡ íë¡ëì
ìì ꜀ ì€ë ìê° ëì ìŽ ì룚ì
ì ì¬ì©íê³ ììŒë©° ìŽ ë¬žì ë ë°ìíì§ ììì§ë§ ì°ë € ì¬íì ìë €ì£Œìžì.
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' }
ë°ëªš - ìµì ìì strictNullCheck íì±í
íìí ê²œì° nullable íìŽë¡ëë ë§ë€ ì ììµëë€. ëŽ ê°ìŽëìì ììží ìœì ì ììµëë€. https://github.com/piotrwitek/react-redux-typescript-guide#actions
ëëšžì§ ì í ìŽ ë³í©ëë©Ž ìŽ êž°ë¥ì íµíŽ ìœê² 구묞 ì€íì ë§ë€ ì ììµëë€.
ì í ëìŒì± ë
ŒëŠ¬ë ì격íŽìŒ í©ëë€. ëìŒí ìì±ì ê°ì§ ì í ëë ë¶ëªš ì íìŽ ëìŒí ìì±ì ê°ë ë°©ììŒë¡ ìžì€íŽì€íí ì ìë ëëšžì§ ìì±ìŽ ìë ì íë§ ìŒì¹íë ê²ìŒë¡ ê°ì£Œë©ëë€. ìŽì ë²ì 곌ì ížíì±ì ì ì§íêž° ìíŽ í©ì± ëëšžì§ ì íìŽ ìŽë¯ž ì¡Žì¬íì§ ìë í 몚ë ì íì ì¶ê°ë©ëë€. ì íëê·ž --strictTypes
ë ì¶ê°ëìŽ í©ì± ëëšžì§ ë§€ê°ë³ìì ì¶ê°ë¥Œ ìµì í©ëë€.
--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;
ìŽ ë ìŽì ì€ë¥ê° ëì§ ììŒë©°, ë€ì ì€ë ë íì 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)
íšìë ëŽ ëŒìŽëžë¬ëŠ¬ ì€ íëìì ë€ì íšì륌 구ííê³ ì¶ìµëë€.
const checkType = <T>() => <U extends Exact<T>>(value: U) => value;
ìŠ, ì íí ëìŒí ì íì 맀ê°ë³ì륌 ë°ííë íšììŽì§ë§ ëìì íŽë¹ ì íìŽ ë€ë¥ž ì í(T)곌 ì íí ëìŒí ì íìžì§ ì¬ë¶ë íìží©ëë€.
ë€ìì ë ê°ì§ ì구 ì¬íì 몚ë 충족íêž° ìíŽ ì€íší ìž ë²ì ìëê° í¬íšë ìœê° ìžìì ìž ìì ëë€.
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
ì íì ë§ë€ ì ììµëë€. ( 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
íŽìŒ never
겜ì°ìë§ U
ìëŒë ì ì© ížíëì§ T
, ì륌 ë€ìŽ, ê²œì° 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ìì ì í ì¬í) ì«ì(CorrectObjectìì ì«ì | 묞ììŽ)ëŒë ì 볎륌 ìêž° ë묞ì ëë€. ëë Exactê° ì믞íë ë°ë¥Œ ì못 ìŽíŽíì ìë ììµëë€. 몚ë ì íìŽ ì íí ëìŒíŽìŒ íë€ë ê²ì ë°ë³µì ìŒë¡ ì믞íë ê²ìŽ ìëëŒ ìžë¶ ìì±ì ë°©ì§í ë¿ìŽëŒê³ ìê°íìµëë€.
ì íí ì í ì§ì곌 íì¬ EPCì ëí ë ë€ë¥ž ê³ ë € ì¬íì 늬í©í ë§ì ëë€. ì¶ì¶ ë³ì 늬í©í ë§ì ì¬ì©í ì ìë ê²œì° ì¶ì¶ë ë³ìì ì í 죌ììŽ ëì ëì§ ìë í EPCê° ìì€ëìŽ ë§€ì° ì¥í©íŽì§ ì ììµëë€.
ëŽê° ì íí ì íì ì§ì§íë ìŽì 륌 ëª íí íêž° ìíŽ - 구ë¶ë ê³µì©ì²Žë¥Œ ìí ê²ìŽ ìëëŒ ì² ì ì€ë¥ ë° ì í costtraint륌 ê°ì²Ž 늬í°ëŽê³Œ ëìì ì§ì í ì ìë 겜ì°ë¥Œ ëë¹íì¬ ì못ë êŽë š ìì±ì ìí ê²ì ëë€.
@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
ì íì ì§í©ìŽì§ë§ T
ë ë€ U
(x ëëœ) ëë U
ë T
(y ëëœ)ì íì ì§í©ì
ëë€.
ìŽê²ì T
, U
ëë T & U
ê° ì íí ì íìžì§ ì¬ë¶ì êŽê³ììŽ ìëíŽìŒ í©ëë€.
@magnushiie ì¢ì ì§ì ìŽ ììµëë€. ì íí ì íì ëë¹ê° ë í° ì íì í ë¹ ê°ë¥ì±ì ì íí ì ìì§ë§ ì¬ì í ë ê¹ì ì íì í ë¹ ê°ë¥ì±ì íì©í©ëë€. ë¹ì ì êµì°š í ì ìëë¡ Exact<{ x: number | string }>
ì Exact<{ x: string | boolean }>
ì»ì Exact<{ x: string }>
. í ê°ì§ 묞ì ë 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 죌ì¥ì ì í 맀ê°ë³ìë¡ ë§ëë ê²ì ë¶ê°ë¥íë¯ë¡ ížì¶ ìê° ëì ìŽë£šìŽì žìŒ í©ëë€(ìŠ, ìŽì ëíŽ êž°ìµíŽìŒ íš).
ë€ìì ìëíë ë° íìí ëì°ë¯ž ì ížëŠ¬í°ì ëë€(ìŒë¶ @tycho01 ëë¶ì).
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
)ë êŽì¬ì ê°ì§ ì ììµëë€. :)
êŽì¬ ìë ì¬ëìŽëŒë©Ž íšì 맀ê°ë³ìì ì íí ì íì ì ì©íë ê°ëší ë°©ë²ì ì°Ÿììµëë€. ì ìŽë TS 2.7ìì ìëí©ëë€.
function myFn<T extends {[K in keyof U]: any}, U extends DesiredType>(arg: T & U): void;
ížì§: ìŽê²ìŽ ìëíë €ë©Ž ìžìì ì§ì ê°ì²Ž 늬í°ëŽì ì§ì íŽìŒ í©ëë€. ììì ë³ëì const륌 ì ìžíê³ ëì ì ë¬íë©Ž ìëíì§ ììµëë€. :/ ê·žë¬ë í ê°ì§ íŽê²° ë°©ë²ì ížì¶ ì¬ìŽížìì ê°ì²Ž íì°ì ì¬ì©íë ê²ì
ëë€(ì: myFn({...arg})
.
ížì§: ì£ì¡í©ëë€. TS 2.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ì ì°žì¡°íììì€.
ì¬ì© ì¬ë¡ê° íë ë ììµëë€. ì€ë¥ë¡ ë³Žê³ ëì§ ìì ë€ì ìí© ë묞ì ë²ê·žê° ê±°ì ë°ìíìµëë€.
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 #20863 ìëê°ì? ë žë ì¡°í©ì ëí ìŽê³Œ ì¬ì° íìžìŽ ë ì격íŽì§êž°ë¥Œ ìí©ëë€.
ìŽìšë ì íí ì íìŽ ìê³ ê³µì©ì²Žì ëí ì격í ìŽê³Œ ìì± ê²ì¬ê° ìë ê²œì° ì¡°ê±Žë¶ ì í ì ì¬ì©íë ëì íë¡ê·žëë° ë°©ììŒë¡ ìŽë¬í 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
ê°ì²Žë ëšì§ ê°ì²Ž (íŽëì€ê° ìë)ìŽêž° ë묞ì ì ë¬ë©ëë€. JSë ê°ì²Žì í€/ê° ëì
ë늬륌 구ë¶íì§ ììŒë©° TSë í ë€íì± ì íìŽ ì¶ê°ë ê² ìžìë ì¬êž°ìì ë€ë¥Žì§ ììµëë€. ëí TSë ê° ì¢
ì ì íì ì§ìíì§ ììŒë©° 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
ì íì 구ë³ë ê³µì©ì²Žì ëíŽ ìëë ëë¡ë§ ìëí©ëë€. ë¹ì°šë³ ê³µì©ì²Žì ê²œì° ê³µì©ì²Ž ì íì êµì°š ê° ì ë¬ëë©Ž Typescript 3.2ê° íµê³Œë©ëë€.
as TypeX
ëë as any
륌 ì¬ì©íì¬ ìºì€í
íë ìì íŽê²° ë°©ë²ì 구ì±ìì ì€ë¥ë¥Œ ìšêž°ë ë¶ìì©ìŽ ììµëë€!. ì°ëŠ¬ë typecheckerê° êµ¬ì± ì€ë¥ë¥Œ ì¡ë ë°ë ëììŽ ëꞰ륌 ë°ëëë€! ëí ì ì ìë ì íìì ì ì ìŒë¡ ìì±í ì ìë ëª ê°ì§ íëª©ìŽ ììµëë€. ìì ê°ì íŽê²° ë°©ë²(ëë ì¬êž°ì ì€ëª
ë ëª
목í íŽê²° ë°©ë²: https://gist.github.com/donabrams/74075e89d10db446005abe7b1e7d9481)ìŽ íŽë¹ ìì±êž°ì ìëì ì€ì§í©ëë€( _
ì í íë륌 íí°ë§í ì ìì§ë§ ìŽë ê³ íµì€ë¬ìŽ ê·ì¹ì
ëë€. ê·žê²ì ì ëì ìŒë¡ íŒí ì ììµëë€).
@aleksey-bykov ì°žê³ ë¡ ê·íì 구íìŽ 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;
ìì°, êœì ì¬êž° ëê³ ê°ìžì, ì 묌ì ì ììì ë£ìŽì
ì¬êž°ì í ì ìë ìì ê°ì ì¬í:
Exact
ì ë€ì ì ì륌 ì¬ì©íì¬ A
ìì A
ë° never
ì íìŒë¡ B
륌 A
ì 몚ë í목ì íšê³Œì ìŒë¡ ëºëë€ B
ì ê³ ì í€ë¥Œ ì¬ì©íë©Ž ì못ë ìì±ì ëíŽ ë ìžë¶ì ìž ì€ë¥ê° ë°ìí ì ììµëë€.
type Omit<T, K> = Pick<T, Exclude<keyof T, keyof K>>;
type Exact<A, B = {}> = A & Record<keyof Omit<B, A>, never>;
ë§ì§ë§ìŒë¡ ë ë²ì§ž 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 í¹í ì ì í ì íšì± ê²ì¬ì íìí ê²œì° ìì ìì B
in Exact<A, 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ì ë¬Œë¡ íšì¬ ë ì ì°í©ëë€.
UPD2 DanielìŽ ì€ì ë¡ @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
ì ì í íížë¥Œ 볎ì¬ì£Œììµëë€.
ê·žëì ëëìŽ ì€ë ëì 묞ì ê° ìë€ê³ ìê°íì§ ììµëë€.
ë ë€ë¥ž ë³µì¡ì±ì ì íì ìì±ì ì²ëŠ¬íë ë°©ë²ìŒ ì ììµëë€.
ì íì ìì±ìŽ ìë ì íìŽ ìë ê²œì° íŽë¹ ìì±ì ëí Exact<T>
ë ë€ìì ì믞í©ëë€.
export type PlaceOrderResponse = {
status: 'success' | 'paymentFailed',
orderNumber: string
amountCharged?: number
};
Exact<T>
ë 몚ë ì íì ìì±ì ì ìíŽìŒ íšì ì믞í©ëê¹? 묎ììŒë¡ ì§ì íìê² ìµëê¹? ë°íì íšê³Œê° ìêž° ë묞ì 'ì ìëì§ ìì' ëë 'null'ìŽ ìëëë€.
ìŽì 'íì ì íì 맀ê°ë³ì'륌 ì§ì íë ìë¡ìŽ ë°©ë²ìŽ íìí©ëê¹?
ì륌 ë€ìŽ ë€ì ìœë ìíìì ì íì 'ì íì±'ì 충족ìí€ë €ë©Ž amountCharged
묎ìì í ë¹íŽìŒ í©ëê¹? ì°ëŠ¬ê° ìŽ ìì±ì ìµìí 'ì¹ìž'íëë¡ ê°ì íì§ ìëë€ë©Ž ì°ëŠ¬ë ë§€ì° 'ì í'íì§ ììµëë€. <never>
ì
ëê¹? undefined
ëë null
.
const exactOrderResponse: Exact<PlaceOrderResponse> =
{
status: 'paymentFailed',
orderNumber: '1001',
amountCharged: ????
};
ê·žëì ë¹ì ì ìê°í ì ììµëë€ - ê·žê²ì ì¬ì í ââì í ì¬íìŽë©° ìŽì ë ì í ì¬í ìŒë¡ ë²ìëë ì¬í ì
ëë€. ê·žëŠ¬ê³ íì€í ë°íì ìë ì€ì íì§ ììë ëì§ë§ 묌ìí륌 ë¶ì¬ì Exact<T>
륌 '깚ì§' ê²ì²ëŒ 볎ì
ëë€.
ìŽ íìžìŽ íìí ê²ì ë ì í ì¬ìŽì ê°ì í ë¹í ëë§ ê·žëŽê¹ì? (ë ë€ 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>
ì íìŽ ìëëŒ ë€ì ë ê°ì§ ì€ íëì
ëë€.
NothingMoreThan<T>
ëë
NothingLessThan<T>
'íì ì í ì¬í' ì ìŽì ìŒì ëë€. 첫 ë²ì§žë í ë¹ì RHSì ìíŽ ì¶ê°ë¡ ì ìí ì ìë ê²ìŽ ìê³ ë ë²ì§žë í ë¹ì RHSì 몚ë í목(ì íì ìì± í¬íš)ìŽ ì§ì ëìëì§ íìží©ëë€.
NothingMoreThan
ë ì ì ëë JSON.stringify()
íµíŽ ì ì¡ë íìŽë¡ëì ì ì©íë©° RHSì ë묎 ë§ì ìì±ìŽ ìêž° ë묞ì ì€ë¥ê° ë°ìíë 겜ì°ìë§ ì ííëë¡ ë°íì ìœë륌 ìì±íŽìŒ í©ëë€. íìí ìì±. ê·žê²ìŽ ë°ë¡ ìë°ì€í¬ëŠœížê° ìëíë ë°©ììŽêž° ë묞ì
ëë€.
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
- ê°ë
ì±ì ëêž° ìíŽ ìì ìŒë°ì ìž ê²œì°ì ì€íìŽ ëŽì¥ëìŽ ììµëë€.ìŽê²ì ëí Exact<{a: number}> | Exact<{b: number}>
ì ê°ìŽ ê° ë³í Exact<T>
ë§ë€ìŽ ì¬ì©ì ìììì #14094 륌 구íí ì ìê² í©ëë€.
ìŽê²ìŽ ì¬ì©ì ìììì ë¶ì ì íì ê°ë¥íê² íëì§ë ê¶êží©ëë€. ëë ê·žê²ìŽ ê°ë¥íë€ê³ ìê°íì§ë§ ê·žê²ì íìžíêž° ìíŽ ëšŒì ë³µì¡í ì í ì°ì ì ìííŽìŒíë©° ìŠëª í ê²ìŽ ë¶ëª íì§ ììµëë€.
(super T) | (íì¥ T)ë ì ì ìì곌 ëìŒí©ëë€. ëë ê·žë ë€ê³ ìê°íì§ë§ ê·žê²ì íìžíêž° ìíŽ ëšŒì ë³µì¡í ì í ì°ì ì ìííŽìŒíë©° ìŠëª í ììë ë¶ëª í ê²ì ìëëë€.
(super T) | (extends T) === unknown
ìŽ í ë¹ ê°ë¥ì±ì ì ì§íë €ë©Ž ìŽ ì£Œë¬žìŽ íìí©ëë€.
@jack-williams ì ì¡í ìì ëììµëë€(íŽë ì ì ê±°). ëë ì¡°êž ëë€ê° ì²ìì ìŒìŽ ì íëŠ¬ì§ ìë ìŽì ê° ê¶êžíë€.
@ìì늬ìì€
"ìŽí"ë ê·žë¥ ìŒë°ì ìž ì íì ëë€. TSë ìŽë¥Œ ììì ìŒë¡ ìííë©° 몚ë ì íì ëë±íê² ì²ëŠ¬ë©ëë€.
ì, ìëì. íì§ë§ ëë¶ë¶ ê·žë ìµëë€... ...íì§ë§ strict
몚ëìž ê²œì°ìë§ ê°ë¥í©ëë€!
ê·žëì ë ŒëŠ¬ì ìŒë¡ 'ì íì 'ìŽìŽìŒ íë ìì±ìŽ íìí ìí©ìŽ ë§ìì§ë§ 컎íìŒë¬ê° ëŽê° 'ììê±°ë' ì² ìê° íëŠ°ì§ ìë €ì£Œêž°ë¥Œ ìíìµëë€.
êžì, ê·žê² ì íí ë¹ì ìŽ lastName: string | undefined
ì»ë ê²ì
ëë€. ë°ë©Ž ì ë ëë¶ë¶ lastName?: string
ì»ìê³ , ë¬Œë¡ strict
몚ëê° ììŒë©Ž 몚ë ë¶ìŒì¹ì ëíŽ ê²œê³ ë¥Œ ë°ì§ ìì ê²ì
ëë€.
ëë íì ì격 몚ëì ëíŽ ìê³ ììê³ ìŽì ê¹ì§ ê·žê²ì ìŒì§ ìì ìŽì 륌 íì ëì ì°Ÿì ì ìììµëë€. ) 'ìŠì' ìíë ëìì ì»ë ê²ìŽ íšì¬ ìœìµëë€.
Required<A> extends Required<B>
륌 ê°ì§ê³ ë
žë ê²ê³Œ ?
ìì± íë귞륌 ì ê±°íë €ê³ ìëíë ê²ì í¬íšíì¬ ìíë ê²ì ì»êž° ìíŽ ëªšë ì¢
ë¥ì ìŒì ìëíìµëë€. ê·žê²ì ë륌 ìì í ë€ë¥ž í ëŒ êµ¬ë©ìŒë¡ 볎ëìµëë€. (ê·žëŠ¬ê³ ìŽê²ì ëŽê° strict
몚ë륌 ìŒêž° ì ì 몚ë ê²ìŽììµëë€).
ìì ì ì€ëë 'ì íí' ì íì ê°ê¹ìŽ ê²ì ì»ìŒë €ë©Ž strict
몚ë(ëë íëê·ž ì¡°í©ìŽ ì¬ë°ë¥ž ê²ì¬ë¥Œ ì ê³µíë 몚ë ê²)륌 íì±ííë ê²ìŒë¡ ììíŽìŒ íë€ë ê²ì
ëë€. ê·žëŠ¬ê³ ëì€ì middleName: string | undefined
륌 ì¶ê°íŽìŒ íë ê²œì° ë¶ - ê°ìêž° 'ê³ ë €'íŽìŒ íë 몚ë ê³³ìì ì°Ÿì ì ììµëë€ :-)
ì¶ì . ì견 죌ì
ì ê°ì¬í©ëë€ - ë§€ì° ëììŽëììµëë€. ëë ë¶ëª
í strict
몚ë륌 ì¬ì©íì§ ìë ë§ì ìœë륌 볎ìë€ë ê²ì 깚ë«ê³ ììµëë€. ê·žëŠ¬ê³ ëì ì¬ëë€ì ì ì²ëŒ 벜ì ë¶ëªíëë€. ë ë§ì ì¬ì©ì ì¥ë €íêž° ìíŽ ë¬Žìì í ì ìëì§ ê¶êží©ëë€.
@simeyla ê·íì íŒë백곌 ê°ì¬ë @isiahmeadowsìê² ì ë¬ëìŽìŒ íë€ê³ ìê°í©ëë€!
Ʞ볞 íë¡í íì ì 구íí í Exact ì íì ëí 겜íì ì ìŽìŒê² ë€ê³ ìê°íìµëë€. ëŽ ìŒë°ì ìž ìê°ì íìŽ íê°ë¥Œ ì ëë¡ ìííë€ë ê²ì ëë€.
ì°ëŠ¬ì í¬ë§ì ìž ì§ëšì ìŽê²ìŽ ìëì ìŒë¡ ììì ì§ì ìŒë¡ íìë API륌 ì ìžíê³ ë XY 묞ì ì룚ì ìŽëŒë ê²ì ëë€.
ëë ë ë€ë¥ž ê°ì²Ž ì íì ëì íë ë¹ì©ìŽ ë ë§ì ì€ë¥ë¥Œ í¬ì°©íê±°ë ìë¡ìŽ ì í êŽê³ë¥Œ íì±ííšìŒë¡ìš ê°ëë€ê³ ìê°íì§ ììµëë€. ê¶ê·¹ì ìŒë¡ ì íí ì íì ì¬ì©íë©Ž ë _ë§_í ì ìì§ë§, ëë _í _ ì ììµëë€.
ì íí ì íì ëª ê°ì§ ì ì¬ì ì¬ì© ì¬ë¡ ì¡°ì¬:
keys
ë° for ... in
ëí ê°ë ¥í ì
ë ¥.í€ë¥Œ ìŽê±°í ë ë³Žë€ ì íí ì íì ì¬ì©íë ê²ìŽ ë§€ë ¥ì ìŒë¡ 볎ìŽì§ë§ ì€ì ë¡ë ê°ë ì ìŒë¡ ì íí ê²ì ëí í€ë¥Œ ìŽê±°íë ìì ì ë°ê²¬íì§ ëª»íìµëë€. í€ë¥Œ ì íí ìê³ ìë€ë©Ž ì§ì 죌ì륌 ì§ì íì§ ìë ìŽì ë 묎ìì ëê¹?
í ë¹ ê°ë¥ì± ê·ì¹ { ... } <: { ...; x?: T }
ì ìŒìªœ ì íì ìšëŠ¬ìŽì±ë ížíëì§ ìë x
ìì±ìŽ í¬íšë ì ìêž° ë묞ì ì¬ë°ë¥Žì§ ììµëë€. ì íí ì íìì í ë¹í ë ìŽ ê·ì¹ì 걎ì í©ëë€. ì€ì ë¡ ì ë ìŽ ê·ì¹ì ì¬ì©íì§ ììµëë€. ì²ìë¶í° ì íí ì íìŽ ìë ë ê±°ì ìì€í
ì ë ì í©íŽ 볎ì
ëë€.
ëë props ì ë¬ì ê°ì íê³ ì€íë ë ì íì ëšìííë ì íí ì íì ë§ì§ë§ í¬ë§ì 걞ììµëë€. íì€ì ì íí ì íìŽ ì íë ë€íì±ì ë°ëìŽê³ 귌볞ì ìŒë¡ ë¹êµ¬ì±ì ìŽëŒë ê²ì ëë€.
ì íë ì ë€ëŠì ì¬ì©íë©Ž êŽì¬ ìë ìíì ì§ì íê³ ëëšžì§ë ì ë¬í ì ììµëë€. 겜ê³ê° ì ííŽì§ë©Ž ëë¹ íì ì íìŽ ìì í ì¬ëŒì§ê³ ì ë€ëŠìŽ íšì¬ ë ì ì©íŽì§ëë€. ë ë€ë¥ž 묞ì ë TypeScriptì 죌ì ìì± ë구 ì€ íëê° êµì°šìŽì§ë§ êµì°š ì íì ì íí ì í곌 ížíëì§ ìëë€ë ê²ì ëë€. ì íí êµ¬ì± ììê° ìë ì€ìíì§ ìì êµì°š ââì íì ë¹ìŽ ììµëë€. _ì íí ì íì 구ì±íì§ ììµëë€_. react ë° propsì ê²œì° í ì í곌 í ë€íì±ì ìí ì ìì§ë§ ìŽë ë€ë¥ž ë ì ìí ê²ì ëë€.
ì íí ì íìŒë¡ íŽê²°í ì ìë ê±°ì 몚ë í¥ë¯žë¡ìŽ ë²ê·žë ìŽê³Œ ìì± ê²ì¬ë¡ íŽê²°ë©ëë€. ê°ì¥ í° ë¬žì ë ì°šë³ì ìì±ìŽ ìë ë žëì¡°í©ì ëíŽìë 곌ìì¬ì°ì ê²ìŽ íµíì§ ìëë€ë ì ìŽë€. ìŽê²ì íŽê²°íë©Ž ì íí ì í곌 êŽë šë ê±°ì 몚ë í¥ë¯žë¡ìŽ 묞ì ê° ì¬ëŒì§ëë€. IMO.
@jack-williams ì íí ì íì ê°ë ê²ìŽ ìŒë°ì ìŒë¡ ê·žë€ì§ ì ì©íì§ ìë€ë ë° ëìí©ëë€. ìŽê³Œ ìì± ê²ì¬ ê°ë
ì ì€ì ë¡ ëŽ super T
ì°ì°ì ì ìì ìíŽ ë€ë£šìŽì§ëë€. ëšì§ ê°ì ì ìŒë¡ Tê° í ë¹í ì ìë 몚ë ì íì í©ì§í©ìŽ Tì ì ì í íì ì íì í¬íš íì§ ìêž° ë묞 ì
ëë€.
ëë T super U
*륌 ì ìžíê³ ê°ìžì ìŒë¡ ìŽê²ì í¬ê² ì§ì§íì§ ììµëë€. ìŽê³Œ ìì± ê²ì¬ì ëíŽ ëŽê° 겜í í ì ìŒí ì¬ì© ì¬ë¡ë ê³ ì¥ë ìë²ë¥Œ ë€ë£šë ê²ìŽììµëë€. ìŒë°ì ìŒë¡ ë€ìì íµíŽ íŽê²°í ì ììµëë€. ëíŒ êž°ë¥ì ì¬ì©íì¬ ìëìŒë¡ ìì²ì ìì±íê³ ìŽê³Œ ì°ë Ʞ륌 ì ê±°í©ëë€. ì§êžê¹ì§ ìŽ ì€ë ëìì ë³Žê³ ë ë€ë¥ž 몚ë 묞ì ë ê°ëší ìë³ ì¡°í©ì ì¬ì©íì¬ ê°ëší íŽê²°í ì ììµëë€.
* ìŽê²ì Ʞ볞ì ìŒë¡ ëŽ ì ìì ì¬ì©íì¬ T extends super U
- ííì ë°ê³µë³(contravariant) ì ë€ëŠ ì íì ì ííë ë° ëëë¡ ì ì©íë©° íŽê²° ë°©ë²ì ìŒë°ì ìŒë¡ ëŽ ê²œíì ë°ëŒ ë§ì ì¶ê° ì í ìì©êµ¬ë¥Œ ëì
íê² ë©ëë€.
@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 êµ¬ì± ìì륌 ëíí ë ìŽì ëí ì¬ì© ì¬ë¡ê° ìë ê² ê°ìµëë€. https://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>>;
ìŽ ê²œì° ì€ë¥ê° ë°ìíì§ë§ ì€ë¥ë¥Œ ìŽë»ê² ìì í©ëê¹? ì¬êž°ììë ëíŒ êµ¬ì± ììê° ìì í ëìŒí prop ì íì ê°ê³ ìì§ ììŒë©° ìŽë ìì ìì ì€ì ë¡ prop íì ì§í©ì ëì ìŒë¡ ì¶ì¶íŽìŒ íë€ê³ ê°ì í©ëë€. ìŽê²ì í©ëŠ¬ì ìž ê°ì ì ëê¹?
MyWrapperComponent
propsë ì ííë€ë©Ž destructuring bind륌 íë ê²ìŒë¡ 충ë¶íë€ê³ ìê°í©ëë€. ìŒë°ì ìž ê²œì°ìë ì íí ì íë³Žë€ 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
ë묞ì ìžìì 몚ë ì¡°í©ìì _commonì keys_륌 ì»ì 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)
ë¹êµê° ìëëŒ ìì í ëšê³ë¡íì§ êµ¬ë¶ ìë£ì íšê». ìŽë íì¬ ì믞 첎ê³ìž "for all {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ê° "ê·žë¥ ìë"íëë¡ ìëëìì§ë§ ì€ì ë¡ë ì íì ìŽê³ íŒëì€ëœê³ ìì íì§ ìë€ë ê²ì ì믞íìµëë€. ì£Œë¡ "ê³ ìì ìŒë¡" ì¬ì©íë €ê³ íë©Ž ìŒë°ì ìŒë¡ ë°ì ìŽì ìê² ëêž° ë묞ì ëë€.
ížì§: ì, íŒëì 깚ë¬ìì ë "ê·žë€"ì "ê·žê²"ìŒë¡ ë°êŸžëë¡ ížì§íìµëë€.
@spion
ëí ì íí ì íìŽ "ê·žë¥ ìë"íë€ë ì믞ë ìëëë€. ëë 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
}
bar
ì í ë¹ getUser3
ì€íší©ëë€. 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
륌 ì§ì íê³ ë ë²ì§ž ížì¶ìì 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 ì°žì¡° ì êŽë šë ê²ì ëë€.
/cc @RyanCavanaugh
ë륌 ìí í ê°ì§ ì¬ì© ì¬ë¡ë
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
ë 구ì±ì ì ì©í©ëë€(ë°ëŒì ì¶ê° 맀ê°ë³ì/ì€í륌 묎ìíê³ ì¡°êž°ì ì€íšíì§ ììµëë€).
AtLeast
ë ì¬ì©ìê° ìíë ì¶ê° í목ì ê°ì²Žì ë°ìŽ ë£ì ì ìë ë°ì êµ¬ì± ìì ë° ë¯žë€ìšìŽì ê°ì í목ì ì í©í©ëë€.
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
ëŒë í€ìëê° í¬ìžížëŒê³ ìê°í©ëë€.
ì íí êŽë šìŽ ìëì§ íì€íì§ ìì§ë§ ìŽ ê²œì° ìµì ë ê°ì§ ì€ë¥ê° ììë©ëë€.
ìŽëì¥
@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 ì íìŒë¡ ìë ì¹ê²©íì§ ìììŒë¯ë¡ exact()
ëì°ë¯ž êž°ë¥ìŽ ì¬ì©ë©ëë€. 몚ë ê°ì ì íí ì íìŒë¡ ì¹ê²©ë ì ìì§ë§ TypeScriptê° ííìì ë ë¶ë¶ 몚ëì Ʞ볞 ì íìŽ íì¥ ê°ë¥í ë¿ë§ ìëëŒ ì íí ëìŒíšì ìŠëª
í ì ìë 겜ì°ìë§ í ë¹ìŽ ì±ê³µí©ëë€.
TypeScriptê° extend
êŽê³ ê²ì¬ë¥Œ ì¬ì©íì¬ ì€ë¥žì ì íìŽ ìŒì ì íì í ë¹ë ì ìëì§ ì¬ë¶ë¥Œ ê²°ì íë€ë ì¬ì€ì ìŽì©íì¬ ìëí©ëë€. .
ìžì© checker.ts
,
// ë ê°ì ì¡°ê±Žë¶ ì í 'T1 extends U1 ? X1 : Y1' ë° 'T2ë U2륌 íì¥í©ëê¹? X2 : Y2'ë ë€ì곌 ê°ì ê²œì° êŽë šìŽ ììµëë€.
// T1곌 T2 ì€ íëë ë€ë¥ž íëì êŽë šëê³ U1곌 U2ë ëìŒí ì íìŽë©° X1ì X2ì êŽë šëë©°
// Y1ì Y2ì êŽë šìŽ ììµëë€.
ExactInner<T>
ì ë€ëŠì U1
ë° U2
륌 ì íì± ê²ì¬ê° íìí Ʞ볞 ì íìŒë¡ ë첎íì¬ ì€ëª
ë ì ê·Œ ë°©ìì ì¬ì©í©ëë€. Exact<T>
ë ëì ë³ì ëë íšì ìžìê° ì íí ì íìŽ ìë ë TypeScriptê° ì íí ì íì ìíí ì ìëë¡ ìŒë° Ʞ볞 ì í곌ì êµì°šë¥Œ ì¶ê°í©ëë€.
íë¡ê·žëëšžì êŽì ìì, Exact<T>
íëíë€ ê·žê²ìë ì€ì ê²ì²ëŒ exact
ì íëê·ž T
ê²ì¬ììŽ T
ê·žëŠ¬ê³ ë
늜ì íí륌 ìì±íì§ ìê³ ëë ë³í.
ì¬êž° íë ìŽê·žëŒìŽë ë§í¬ ì ìì§ ë§í¬ê° ììµëë€.
ê°ë¥í í¥í ê°ì ì¬íì ì ííì§ ìì ì íì ì íí ì íìŒë¡ ìë ì¹ê²©íì¬ exact()
êž°ë¥ì íìì±ì ìì í ì ê±°íë ê²ì
ëë€.
ë©ì§ ìí @toriningen!
exact
ížì¶ìì ê°ì ëííì§ ìê³ ë ìŽ ìì
ì ìíí ì ìë ë°©ë²ì ì°Ÿì ì ìë ì¬ëìŽ ìë€ë©Ž ì벜í ê²ì
ëë€.
ìŽê²ìŽ ì¬ë°ë¥ž 묞ì ìžì§ íì€íì§ ìì§ë§ ì¬êž°ì ëŽê° ìŒíê³ ì¶ì ê²ì ìê° ììµëë€.
https://www.typescriptlang.org/play/#code/KYOwrgtgBAyg9gJwC4BECWDgGMlriKAbwCgooBBAZyygF4oByAQ2oYBpSoVhq7GATHlgbEAvsWIAzMCBx4CTfvwDyCQQgBCATwAU -DNlz4AXFABE5GAGEzUAD7mUAUWtmAlEQnjiilWuCauvDI6Jhy + AB0VFgRSHAAqgAOiQFWLMA6bm4A3EA
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 ì룚ì ìŽ ë ë¹ ë¥Žë€ê³ ìê°íêž° ë묞ì @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ë¡ ìžêžë ìŽì ì€ íëììµëë€).
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 ê° ì¢ë€ê³ ìê°í©ëë€. ì ì íì ë§€ì° ì ì¬í©ëë€(ì¶ê° ê²ì¬ ììŽ T extends R
륌 볎ì¥íêž° ìíŽ &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
ìŽ ê°ì§ëë©Ž 묞ì ê° ê²œê³ ë¥Œ ë°íì ë°ìì© ìŽì ì
ëë€ propTypes
ëë defaultProps
ìš render
ìžì륌. ì°ëŠ¬ë ìŽê²ì ì í ìì€ìì íííê³ ì¶ì§ë§ 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
ê° í¬íšë ì€ë¥ ë©ìì§ë ëììŽ ëì§ ììµëë€("{}ë undefinedì í ë¹í ì ììµëë€").
@toriningen ì ì룚ì ìŽ ë€ë¥ž ìŽë²€íž ê°ì²Ž 몚ìì ì¡°í©ìŒë¡ ìŽë»ê²
type StoreEvent =
| { type: 'STORE_LOADING' }
| { type: 'STORE_LOADED'; data: unknown[] }
ìŽë²€ížì ì íí 몚ìë§ íì©íë íìíë dispatch() íšì륌 ìŽë»ê² ë§ë€ ì ìëì§ ëª ííì§ ììµëë€.
(ì ë°ìŽíž: ììëìµëë€: https://gist.github.com/sarimarton/d5d539f8029c01ca1c357aba27139010)
ì¬ì© ì¬ë¡:
Exact<>
ì§ììŽ ììŒë©Ž GraphQL ë³íì ë°íì 묞ì ê° ë°ìí©ëë€. GraphQLì íì©ëë ìì±ì ì íí 목ë¡ì íì©í©ëë€. props륌 곌ëíê² ì ê³µíë©Ž ì€ë¥ê° ë°ìí©ëë€.
ë°ëŒì ìììì ìŒë¶ ë°ìŽí°ë¥Œ ì»ì ë 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 = {
ëª
ìì ìŒë¡ 죌ìì ë¬ë©Ž ëììŽ ëì§ë§ ìœë ê²í ìì ë°ê²¬íê³ ì ì©íêž°ê° ìœê° ë²ê±°ë¡ê³ ìŽë µìµëë€.
ìŽê²ì ë€ì 죌ì 륌 ë²ìŽë ììŽëìŽìŽë©° ì¬êž°ì ì€ëª ë ì íì±ì ëí ëë¶ë¶ì ì¬ì© ì¬ë¡ë¥Œ íŽê²°íì§ ëª»í©ëë€. ê·žë¬ë ëë¬ìžë ë²ì ëŽìì í ë²ë§ ì¬ì©ëë ê²œì° ê°ì²Ž 늬í°ëŽì ì ì íê² ì ì§í ì ììµëê¹?
@RyanCavanaugh 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ê° ëª ë
ì ì ì€ë ëìì ìžêží :-) "ì¬ì© ì¬ë¡ê° ìë ê²") ìž¡ë©Žìì ëŽê° ìíë ë ê°ì§ ì¬ì© ì¬ë¡ Exact
ì¬ì©:
ë°ìŽí° ì ì¥ì/ë°ìŽí°ë² ìŽì€/ORMìŒë¡ ë°ìŽí° ì ë¬--ì ë¬ë ì¶ê° íëë ìëìŒë¡ ìì /ì ì¥ëì§ ììµëë€.
ì ì ížì¶ / RPC / REST / GraphQLì ë°ìŽí°ë¥Œ ì ë¬íë©Ž ì ë¬ëë ì¶ê° íëê° ìëìŒë¡ ìì ëê±°ë ì ì¡ëì§ ììµëë€.
(ì, ìë§ ìëìŒë¡ ìì ëì§ë ììì ê²ì ëë€. ë°íì ì€ë¥ìŒ ì ììµëë€.)
ë ê²œì° ëªšë íë¡ê·žëëšž/ë ìì ìê² (컎íìŒ ì€ë¥ë¥Œ íµíŽ) "... 'ì ì¥' ëë ' 볎ëžë€'ë ê²ìŽë€.
ìŽê²ì "ë¶ë¶ ì ë°ìŽíž" ì€íìŒ API, ìŠ ìœí ì íìì í¹í íìí©ëë€.
type Data = { firstName:? string; lastName?: string; children?: [{ ... }] };
const data = { firstName: "a", lastNmeTypo: "b" };
await saveDataToDbOrWireCall(data);
ìœí ì í ê²ì¬ b/cì ìŒì¹íë íë ìŽìì 맀ê°ë³ì 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 ìŽê²ì user-land" ë°ìŽí° í¬ìžížìì íêž° ìŽë µìµëë€.)
ìŽëŽ,
ì íí ì íì ë ìœë ë° íí ì ìì ëí 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
};
Exactë API ìëµì ë°íí ë ë§€ì° ì ì©í©ëë€. íì¬ ë€ì곌 ê°ìŽ íŽê²°í©ëë€.
const response = { companies };
res.json(exact<GetCompaniesResponse, typeof response>(response));
export function exact<S, T>(object: Exact<S, T>) {
return object;
}
ì¬êž°ì Exact
ì íì @ArnaudBarre ê° ììì ì ê³µí ê²ì
ëë€.
ì 륌 ì°šëš íŽì íê³ ëª ê°ì§ë¥Œ ê°ë¥Žì³ì£Œì @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 ì ì견곌 ë§ì°¬ê°ì§ë¡ ... 몚ë 겜ì°ê° ì²ëŠ¬ëìëì§ íì€íì§ ììŒë¯ë¡ ymmv ...
@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
ê° íì ê°ì²Žìž graphQL APIì íìíìµëë€.
ìŽ ë¬žì 륌 íŽê²°íë €ë©Ž ExactObjectì ExactArray륌 ë¶ëŠ¬íê³ ë ì€ íëì ë€ìŽê°ë ì§ì ì ìŽ ììŽìŒ í©ëë€.
ê·žë ë€ë©Ž ê°ì²Žê° ê·ž ìŽìë ê·ž ìŽíë ìë ì íí ìì±ì ê°ëë¡ íë ê°ì¥ ì¢ì ë°©ë²ì 묎ìì ëê¹?
@captain-yossarianì TypeScript íìŽ ìŽê²ì 구ííëë¡ ì€ëí©ëë€. ì¬êž°ì ì ìë ì룚ì ì ììëë 몚ë 겜ì°ì ìëíì§ ììŒë©° ê±°ì ââ몚ë 겜ì°ì ëª íì±ìŽ ë¶ì¡±í©ëë€.
@toriningen ì TS íìŽ ìŽ êž°ë¥ì 구íí ê²œì° ìŒë§ë ë§ì 묞ì ê° íŽê²°ë ì§ ììí ì ììµëë€.
@RyanCavanaugh
íì¬ ì 륌 ì¬êž°ë¡ ë°ë €ìš í ê°ì§ ì¬ì© ì¬ë¡ê° ììŒë©° "êž°í"ëŒë 죌ì ë¡ ë°ë¡ ì°ê²°ë©ëë€. ë€ì곌 ê°ì êž°ë¥ì ìí©ëë€.
ìŽë¬í ìŠê°ì ìž ëª©íë ë€ì곌 ê°ì 목ì ì ë¬ì±í©ëë€.
ëŽ ê²œì°ë¥Œ ë€ì곌 ê°ìŽ ì€ììµëë€.
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ì ë°ë¥ž Weak Type Detectionì ìŽ ë¬žì ë ìì íŽìŒ íë©°, ëŽ ì¬ì© ì¬ë¡ì ë°ëŒ 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ì êŽë šíì¬ ì¬ì í 묞ì ê° ìë ì¬ëìŽ ììµëê¹?
ì í 죌ìì ëí 믞ìí ììŽëìŽê° ììµëë€. ìŒì¹íë ê°ì²Žë ì íí ê°ì ì ìë 구ì±ììŒë¡ ëë©ëë€. ëë ë§ê³ ëë ë§ê³ , ëë ë§ê³ ëë ë§ê³ , ëë ë§ê³ ëë ë§ê³ . ìì ê° ê²œì°ì ëíŽ íëì ííììŽ ììŽìŒ í©ëë€.
ì íí ê°ì, ìŠ ëë ë§ê³ ëë ë§ê³ :
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> {
// ...
}
ê·žë¬ë ëë ë¹ì ìŽ ë ëì ììŽëìŽë¥Œ ê°ì§ê³ ìë€ê³ íì í©ëë€. í¹í ìŽê²ì ë°í ê°ìë§ ìí¥ì 믞ì¹ë ê²ìŽ ìëêž° ë묞ì
ëë€. ê·žë ì£ ? ìŽìšë , ê·žë¥ ìì¬ ìœë ë°ëªšì
ëë€. ëë ê·žê²ìŽ ì€ë¥ì ë¶ì¡±ì íŒíë ì¢ì êž°ë¥ìŽëŒê³ ìê°í©ëë€. ììì ì€ëª
í 겜ì°ì²ëŒ. ë ë€ë¥ž ì룚ì
ì ìë¡ìŽ ì ížëŠ¬í° ì íì ì¶ê°íë ê²ì
ëë€.
ìëë©Ž ëŽê° ëê°ë¥Œ ëì³€ëì? ìŽê²ì ìŽë¯ž ìëí©ëê¹? ì ë TypeScript 4륌 ì¬ì©í©ëë€.
ê°ì¥ ì ì©í ëêž
ì°ëŠ¬ë ìŽê²ì ëíŽ êœ€ ì€ë«ëì ìŽìŒêž°íìµëë€. ëë í ë¡ ì ììœíë €ê³ ë žë ¥í ê²ìŽë€.
ìŽê³Œ ì¬ì° íìž
ì íí ì íì ì¶ê° ìì±ì ê°ì§íë ë°©ë²ìŒ ë¿ì ëë€. ì íí ì íì ëí ììë ì²ìì ìŽê³Œ ìì± ê²ì¬(EPC)륌 구ííì ë ë§ìŽ ëšìŽì¡ìµëë€. EPCë ìë§ë ì°ëŠ¬ê° ì·ší ê°ì¥ í° íêž°ì ìž ë³íìì ê²ì ëë€. EPC ê° ìŽê³Œ ìì±ì ê°ì§
ì¬ëë€ìŽ ì íí ì íì ìíë ëë¶ë¶ì ê²œì° ì°ëŠ¬ë EPC륌 ë ëëíê² ë§ë€ìŽ ìŽë¥Œ ìì íë ê²ì ì íží©ëë€. ì¬êž°ìì íµì¬ ììì ëì ì íìŽ ê³µì©ì²Ž ì íìŒ ëì ëë€. ì°ëŠ¬ë ìŽê²ì ë²ê·ž ìì ìŒë¡ ê°ì£Œíê³ ì¶ìµëë€(EPC ë ì¬êž°ìì ìë
몚ë ìµì ì í
EPCì êŽë šë ê²ì 몚ë ì íì ì í(ì ë "ìœí" ì íìŽëŒê³ íš)ì 묞ì ì ëë€. ëë¶ë¶ì ìœí ì íì ì ííꞰ륌 ìí ê²ì ëë€. ìœí ì í ê°ì§ë¥Œ 구ííŽìŒ í©ëë€(#7485 / #3842). ì¬êž°ì ì ìŒí ë°©íŽ ììë 구íì ìœê°ì ì¶ê° ë³µì¡ì±ìŽ íìí êµì°š ì íì ëë€.
ë구ì ì íìŽ ì íí©ëê¹?
ì íí ì íìì 볌 ì ìë 첫 ë²ì§ž 죌ì 묞ì ë ì íí ì íìŒë¡ íìíŽìŒ íë ì íìŽ ì ë§ ë¶ë¶ëª íë€ë ê²ì ëë€.
ì€íížëŒì í쪜 ëìë ê³ ì ë ëë©ìž ìžë¶ì ì첎 í€ê° ìë ê°ì²Žê° 죌ìŽì§ë©Ž 묞ì ê·žëë¡ ììžë¥Œ ëì§ê±°ë ëì ìŒì íë íšìê° ììµëë€. ìŽê²ë€ì ê±°ì ììµëë€(êž°ìµìì ì륌 ë€ ì ììµëë€). ì€ê°ì ì¡°ì©í 묎ìíë êž°ë¥ìŽ ììµëë€.
ì ì ìë ìì±(ê±°ì 몚ë). ê·žëŠ¬ê³ ë€ë¥ž 쪜 ëìë ìŒë°ì ìŒë¡ 몚ë ìì±ì ëíŽ ìëíë íšìê° ììµëë€(ì:
Object.keys
).ë¶ëª í "ì¶ê° ë°ìŽí°ê° 죌ìŽì§ë©Ž throw" íšìë ì íí ì íì íì©íë ê²ìŒë¡ íìëìŽìŒ í©ëë€. ê·žë¬ë ì€ê°ì ìŽë»ìµëê¹? ì¬ëë€ì ìë§ ëìíì§ ìì ê²ì ëë€.
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)
ì(ë) ë¬Žìš ë»ìžê°ì? :íŒëì€ë¬ìŽ:ì¢ ì¢ ë¹ì ìŽ ì ë§ë¡ ìíë ê²ìŽ "ìë ë¶ëŠ¬ë(auto-disjointed)" í©ì§í©ìž ê²œì° ì íí ì íìŽ ì구ë©ëë€. ìŠ,
{ 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륌 ì¬ì©íì¬ "ëì" ìì±ì ê°ì§íŽìŒ í©ëë€. ë°ëŒì 묞ì ê° ìê³ ì íí ì íìŽ ì¬ë°ë¥ž ì룚ì ìŽëŒê³ ìê°íë ê²œì° ì¬êž°ì ìë 묞ì 륌 ì€ëª íì¬ íšíŽ 칎íë¡ê·žë¥Œ 구ì±íê³ ë 칚ìµì ìŽê±°ë íŒëì€ë¬ìŽ ë€ë¥ž ì룚ì ìŽ ìëì§ íìží ì ìëë¡ íììì€.