JavaScriptã©ã€ãã©ãª/ãã¬ãŒã ã¯ãŒã¯/ãã¿ãŒã³ã®å€ãã¯ããªããžã§ã¯ãã®ããããã£åã«åºã¥ããèšç®ã䌎ããŸãã ããšãã°ãããã¯ããŒã³ã¢ãã«ãé¢æ°å€æpluck
ã ImmutableJSã¯ããã¹ãŠãã®ãããªã¡ã«ããºã ã«åºã¥ããŠããŸãã
//backbone
var Contact = Backbone.Model.extend({})
var contact = new Contact();
contact.get('name');
contact.set('age', 21);
// ImmutableJS
var map = Immutable.Map({ name: 'François', age: 20 });
map = map.set('age', 21);
map.get('age'); // 21
//pluck
var arr = [{ name: 'François' }, { name: 'Fabien' }];
_.pluck(arr, 'name') // ['François', 'Fabien'];
ãããã®äŸã§ã¯ãAPIãšåºã«ãªãåå¶çŽã®é¢ä¿ãç°¡åã«ç解ã§ããŸãã
ããã¯ããŒã³ã¢ãã«ã®å Žåãããã¯æ¬¡ã®ã¿ã€ãã®ãªããžã§ã¯ãã®äžçš®ã®_proxy_ã§ãã
interface Contact {
name: string;
age: number;
}
pluck
å Žåãããã¯å€æã§ã
T[] => U[]
ããã§ãUã¯T prop
ããããã£ã®ã¿ã€ãã§ãã
ããããTypeScriptã§ãã®ãããªé¢ä¿ãè¡šçŸããæ¹æ³ã¯ãªããæçµçã«ã¯åçåã«ãªããŸãã
ææ¡ããã解決çã¯ãåT[prop]
æ°ããæ§æãå°å
¥ããããšã§ããããã§ã prop
ã¯ãæ»ãå€ãåãã©ã¡ãŒã¿ãŒãªã©ã®åã䜿çšããé¢æ°ã®åŒæ°ã§ãã
ãã®æ°ããåã®æ§æã䜿çšãããšã次ã®å®çŸ©ãèšè¿°ã§ããŸãã
declare module Backbone {
class Model<T> {
get(prop: string): T[prop];
set(prop: string, value: T[prop]): void;
}
}
declare module ImmutableJS {
class Map<T> {
get(prop: string): T[prop];
set(prop: string, value: T[prop]): Map<T>;
}
}
declare function pluck<T>(arr: T[], prop: string): Array<T[prop]> // or T[prop][]
ãã®ããã«ãBackboneã¢ãã«ã䜿çšãããšãTypeScriptã¯get
ããã³set
åŒã³åºããæ£ããåãã§ãã¯ã§ããŸãã
interface Contact {
name: string;
age: number;
}
var contact: Backbone.Model<Contact>;
var age = contact.get('age');
contact.set('name', 3) /// error
prop
å®æ°æããã«ãå®æ°ã¯ã€ã³ããã¯ã¹åãšããŠäœ¿çšã§ããåã§ãªããã°ãªããŸããïŒ string
ã number
ã Symbol
ïŒã
Map
å®çŸ©ãèŠãŠã¿ãŸãããã
declare module ImmutableJS {
class Map<T> {
get(prop: string): T[string];
set(prop: string, value: T[string]): Map<T>;
}
}
T
ãã€ã³ããã¯ã¹å¯èœã§ããå Žåããããã¯ãã®åäœãç¶æ¿ããŸãã
var map = new ImmutableJS.Map<{ [index: string]: number}>;
ããã§ã get
ã¿ã€ãã¯get(prop: string): number
ãŸãã
ããã§ã_æ£ãã_åäœãèããã®ã«èŠåŽããå ŽåããããŸãã Map
å®çŸ©ããå§ããŸãããã
ã¿ã€ããã©ã¡ãŒã¿ãšããŠ{ [index: string]: number }
ãæž¡ã代ããã«ã
{ [index: number]: number }
ã³ã³ãã€ã©ããšã©ãŒãçºçãããå¿
èŠããããŸããïŒ
å®æ°ã®ä»£ããã«propã®åçåŒã§pluck
ã䜿çšããå ŽåïŒ
var contactArray: Contact[] = []
function pluckContactArray(prop: string) {
return _.pluck(myArray, prop);
}
ãŸãã¯ããã©ã¡ãŒã¿ãšããŠæž¡ãããã¿ã€ãã®ããããã£ã§ã¯ãªãå®æ°ã䜿çšããŸãã
ã³ã³ãã€ã©ãã¿ã€ãT[prop]
æšæž¬ã§ããªãããã pluck
ã®åŒã³åºãã§ãšã©ãŒãçºçããå Žåã T[prop]
ã{}
ãŸãã¯any
ããããããªãã --noImplicitAny
ã®ã³ã³ãã€ã©ã¯ãšã©ãŒãçºçãããã¹ãã§ããïŒ
ïŒ394ã®éè€ã®å¯èœæ§
https://github.com/Microsoft/TypeScript/issues/1003#issuecomment-61171048ãåç §ããŠ
@ NoelAbrahams ïŒ394ã®è€è£œã ãšã¯æããŸããããéã«äž¡æ¹ã®æ©èœã¯æ¬¡ã®ããã«ããªãè£å®çã§ãã
class Model<T> {
get(prop: memberof T): T[prop];
set(prop: memberof T, value: T[prop]): void;
}
çæ³çã ãã
@fdecampredon
contact.set(Math.random() >= 0.5 ? 'age' : 'name', 13)
ãã®å Žåã¯ã©ãããã°ããã§ããïŒ
ããã¯ç§ã®åé¡ã®æåŸã®æ®µèœããã®ãã®ãšå€ããå°ãªããåãã±ãŒã¹ã§ãã è€æ°ã®éžæè¢ããããšèšã£ãããã«ããšã©ãŒãå ±åãããã any
ã«å¯ŸããŠT[prop]
any
ãæšæž¬ããããšãã§ããŸãã2çªç®ã®è§£æ±ºçã¯ããè«ççã ãšæããŸã
çŽ æŽãããææ¡ã åæããŸããããã¯äŸ¿å©ãªæ©èœã§ãããã
@fdecampredon ãããã¯éè€ããŠãããšæããŸãã Danããã®membertypeof
ææ¡ãå«ã察å¿ããå¿çãåç
§ããŠãã ããã
IMOã¯ãã¹ãŠãããªãçããŠãŒã¹ã±ãŒã¹åãã®å€ãã®æ°ããæ§æã§ãã
@NoelAbrahamsããã¯åãã§ã¯ãããŸããã
memberof T
ã¯ãã€ã³ã¹ã¿ã³ã¹ãT
ã€ã³ã¹ã¿ã³ã¹ã®æå¹ãªããããã£åãæã€æååã®ã¿ã§ããå¯èœæ§ãããã¿ã€ããè¿ããŸããT[prop]
ã¯ã prop
åŒæ°/å€æ°ã§è¡šãããæååã§ååãä»ããããT
ã®ããããã£ã®ã¿ã€ããè¿ããŸããmemberof
ãžã®ããªããžãããããã®ã¿ã€ãã®prop
ãã©ã¡ãŒã¿ãŒã¯memberof T
å¿
èŠããããŸãã
å®ã¯ãåã¡ã¿ããŒã¿ã«åºã¥ããåæšè«ã®ã·ã¹ãã ããã£ãšå
å®ãããããšæã£ãŠããŸãã ãããããã®ãããªæŒç®åã¯memberof
ãšåæ§ã«è¯ãã¹ã¿ãŒãã§ãã
ããã¯èå³æ·±ããæãŸããããšã§ãã TypeScriptã¯ãŸã æååã®å€ããã¬ãŒã ã¯ãŒã¯ã§ã¯ããŸãæ©èœãããããã¯æããã«å€§ãã«åœ¹ç«ã¡ãŸãã
TypeScriptã¯æååã®å€ããã¬ãŒã ã¯ãŒã¯ã§ã¯ããŸãæ©èœããŸãã
æ¬åœã ããã§ãããããéè€ããææ¡ã§ãããšããäºå®ã¯å€ãããŸããã
ããã§ããããã¯æããã«[æååã®å€ããã¬ãŒã ã¯ãŒã¯ãå ¥åããã®ã«]倧ãã«åœ¹ç«ã¡ãŸãã
ããã«ã€ããŠã¯ããããããŸããã ããªãæççã§ãäžã§æŠèª¬ãããããã·ãªããžã§ã¯ããã¿ãŒã³ã«ããããåºæã®ããã§ãã ïŒ1003ã«æ²¿ã£ãããžãã¯ã¹ããªã³ã°ã®åé¡ã«å¯ŸããŠãããå æ¬çãªã¢ãããŒããæãã§ããŸãã
any
ãææ¡ããŠããŸãã ãã®ææ¡ã¯ãå€ã®ã¿ã€ããæ€çŽ¢ããæ¹æ³ãè¿œå ããããšã§ã次ã®ãããªçµæã«ãªãããšãè¿œå ããŸããdeclare module ImmutableJS {
class Map<T> {
get(prop: memberof T): T[prop];
set(prop: memberof T, value: T[prop]): Map<T>;
}
}
@ spion ãïŒ394ã®ããšã§ããïŒ ããã«èªã¿é²ãããšã次ã®ããã«è¡šç€ºãããŸãã
æ»ãå€ã®åãèããŸããããå šäœçãªææ¡ã倧ãããªããããªãããã«çç¥ããŸããã
ããã¯ç§ã®æåã®èãã§ããããåé¡ããããŸãã ã¿ã€ã
memberof T
åŒæ°ãè€æ°ããå Žåãmembertypeof T
ã¯ã©ããåç §ããŸããïŒ
get(property: memberof T): membertypeof T;
set(property: memberof T, value: membertypeof T);
ããã¯ãç§ãåç §ããŠããåŒæ°ãã®åé¡ã解決ããŸããã
membertypeof
ååã¯ééã£ãŠããããã§ãããããã£åãã¿ãŒã²ããã«ããŠããæŒç®åã®ãã¡ã³ã§ã¯ãããŸããã
get(property: memberof T): membertypeof property;
set(property: memberof T, value: membertypeof property);
ããã¯ããŸããããšæããŸãã
get(property: memberof T is A): A;
set(property: memberof T is A, value: A)
æ®å¿µãªãããæåŸã®ææ¡ã«ã¯ãŸãšããªå¯èœæ§ããããšæããŸãããç§ãçŽ æŽããã解決çãæã£ãŠãããã©ããã¯ããããŸããã
OK @ NoelAbrahams ïŒ394ã«ããããšã»ãŒåãããšã説æããããšããŠããã³ã¡ã³ãããããŸããã
ããŠã T[prop]
ã¯ããããããã®ã³ã¡ã³ãã®ããŸããŸãªææ¡ãããå°ããšã¬ã¬ã³ãã§ããããã®åé¡ã®ææ¡ã¯ããããããå°ãåçããŠãããšæããŸãã
ãããã®çç±ãããç§ã¯ãããéè€ãšããŠéããããã¹ãã§ã¯ãªããšæããŸãã
ããããç§ã¯åé¡ãæžãã人ãªã®ã§ãç§ã¯åèŠããããšæããŸã;ïŒã
@fdecampredon ããã£ãšæ¥œããïŒsmileyïŒ
@NoelAbrahamsãã£ãšãç§ã¯ãã®éšåãéããŸããã 確ãã«ããããã¯ã»ãšãã©åçã§ãïŒããã¯å¥ã®æ±çšãã©ã¡ãŒã¿ãŒãå°å ¥ããŠããªãããã§ãããåé¡ãããå Žåãšãªãå ŽåããããŸãïŒ
FlowãèŠãŠã¿ããšãã¢ãããã¯ãªåã®çµã蟌ã¿ããããå°ã匷ãåã·ã¹ãã ãšç¹æ®ãªåã®æ¹ããšã¬ã¬ã³ãã ãšæããŸãã
ããšãã°ã get(prop: string): Contact[prop]
ã§æå³ããã®ã¯ãäžé£ã®å¯èœãªãªãŒããŒããŒãã§ãã
interface Map {
get(prop : string) : Contact[prop];
}
// is morally equivalent to
interface Map {
get(prop : "name") : string;
get(prop : "age") : number;
}
&
åæŒç®åïŒäº€å·®åïŒãååšãããšä»®å®ãããšãããã¯åçã®åã§ãã
interface Map {
get : (prop : "name") => string & (prop : "age") => number;
}
éãžã§ããªãã¯ã±ãŒã¹ãç¹å¥ãªåŠçãªãïŒ [prop]
ïŒã®ååŒã®ã¿ã«å€æããã®ã§ããã©ã¡ãŒã¿ãŒã®åé¡ã«å¯ŸåŠã§ããŸãã
ã¢ã€ãã¢ã¯ãåãã©ã¡ãŒã¿ãŒãããã®åãããããçæããããšã§ãã ããã€ãã®ç¹å¥ãªãããŒãžã§ããªãã¯å$MapProperties
ã $Name
ãããã³$Value
ãå®çŸ©ããŠãçæãããåãååŒã®ã¿ïŒç¹å¥ãªæ§æãªãïŒã§è¡šçŸããåãã§ãã«ãŒããã³ãã«ããããšãã§ããŸããäœãããã¹ãã ãšã
class Map<T> {
get : $MapProperties<T, (prop : $Name) => $Value>
set : $MapProperties<T, (prop : $Name, val : $Value) => void>
}
è€éã§ãã³ãã¬ãŒãã«è¿ãããŸãã¯è²§ãã人ã«äŸåããã¿ã€ãã®ããã«èŠãããããããŸãããã誰ããã¿ã€ããå€ã«äŸåããããå Žåã¯é¿ããããŸããã
ããã圹ç«ã€ãã1ã€ã®é åã¯ãåæå®ããããªããžã§ã¯ãã®ããããã£ãå埩åŠçããããšã§ãã
interface Env {
// pretend this is an actually interesting type
};
var actions = {
action1: function (env: Env, x: number) : void {},
action2: function (env: Env, y: string) : void {}
};
// actions has type { action1: (Env, number) => void; action2: (Env, string) => void; }
var env : Env = {};
var boundActions = {};
for (var action in actions) {
boundActions[action] = actions[action].bind(null, env);
}
// boundActions should have type { action1: (number) => void; action2: (string) => void; }
ãããã®åã¯ãå°ãªããšãçè«çã«ã¯æšæž¬ã§ããã¯ãã§ãïŒ for
ã«ãŒãã®çµæãæšæž¬ããã®ã«ååãªåæ
å ±ããããŸãïŒããããããããªãã®ç¯å²ã§ãã
次ã®ããŒãžã§ã³ã®reactã¯ããã®ã¢ãããŒãã®æ©æµã倧ãã«åããããšã«æ³šæããŠãã ãããhttpsïŒ//github.com/facebook/react/issues/3398ãåç §ããŠ
https://github.com/Microsoft/TypeScript/issues/1295#issuecomment -64944856ã®ããã«ãæååãæååãªãã©ã«ä»¥å€ã®åŒã«ãã£ãŠæäŸãããå Žåããã®æ©èœã¯åæ¢åé¡ã®ããã«ããã«æ©èœããªããªããŸãã ãã ããããã®åºæ¬ããŒãžã§ã³ã¯ãES6ã·ã³ãã«åé¡ïŒïŒ2012ïŒããã®åŠç¿ã䜿çšããŠå®è£ ã§ããŸããïŒ
æ¿èªãããŸããã
æ§æã®æ觊ãã€ããããã«ããããå®éšçãªãã©ã³ãã§è©ŠããŠã¿ãããšæããŸãã
ææ¡ã®ã©ã®ããŒãžã§ã³ãå®è£
ãããã®ãçåã«æã£ãŠããŸããïŒ ã€ãŸãã T[prop]
ã¯åŒã³åºããµã€ãã§è©äŸ¡ãããç±å¿ã«å
·äœçãªåã«çœ®ãæããããã®ã§ããããããããšãæ°ãã圢åŒã®åå€æ°ã«ãªãã®ã§ããããã
ïŒ3779ã§å®çŸ©ãããŠããããã«ãããäžè¬çã§åé·æ§ã®äœãæ§æã«äŸåããå¿ èŠããããšæããŸãã
interface Map<T> {
get<A>(prop: $Member<T,A>): A;
set<A>(prop: $Member<T,A>, value: A): Map<T>;
}
ãããšããAã®ã¿ã€ããæšæž¬ããããšã¯ã§ããŸãããïŒ
éåžžã®è§£æ±ºçãåŸ ã£ãŠããéã«ãImmutableJSãšã®TSçµ±åãç°¡åã«ããããã®å°ããªcodegenããŒã«ãäœæãããšèšãããã ãã§ãïŒ https ïŒ//www.npmjs.com/package/tsimmutable
ãŸããã¡ã³ããŒã¿ã€ãã®ãœãªã¥ãŒã·ã§ã³ã¯ãImmutableJSã§ã¯æ©èœããªãå¯èœæ§ãããããšã«æ³šæããŠãã ããã
interface Profile {
firstName: string
}
interface User {
profile: Profile
}
let a: Map<User> = fromJS(/* ... */);
a.get('profile') // Type will be Profile, but the real type is Map<Profile>!
@ s-panferovãã®ãããªãã®ãæ©èœããå¯èœæ§ããããŸãïŒ
interface ImmutableMap<T> {
get<A extends boolean | number | string>(key : string) : A;
get<A extends {}>(key : string) : ImmutableMap<A>;
get<E, A extends Array<any>>(key : string) : ImmutableList<E>;
}
interface Profile {
}
interface User {
name : string;
profile : Profile;
}
var map : ImmutableMap<User>;
var name = map.get<string>('name'); // string
var profile = map.get<Profile>('profile'); // ImmutableMap<Profile>
ããã¯DOMããŒããŸãã¯Dateãªããžã§ã¯ããé€å€ããŸããããäžå€ã®æ§é ã§ãããã䜿çšããããšãèš±å¯ããã¹ãã§ã¯ãããŸããã https://github.com/facebook/immutable-js/wiki/Converting-from-JS-objects
æåã«çŸåšå©çšå¯èœãªæåã®åé¿çããå§ããŠãããããåŸã ã«è§£æ±ºããŠãããšäŸ¿å©ã ãšæããŸãã
å«ãŸããŠããéããªããã£ããªããžã§ã¯ãã®ããããã£ã®å€ãè¿ãé¢æ°ãå¿ èŠã ãšããŸãããã
function getProperty<T extends object>(container: T; propertyName: string) {
return container[propertyName];
}
ããã§ãæ»ãå€ã«ã¿ãŒã²ããããããã£ã®åãæããããã®ã§ããã®åã«å¥ã®ãžã§ããªãã¯åãã©ã¡ãŒã¿ãŒãè¿œå ã§ããŸãã
function getProperty<T extends object, P>(container: T; propertyName: string) {
return <P> container[propertyName];
}
ãããã£ãŠãã¯ã©ã¹ã®ãŠãŒã¹ã±ãŒã¹ã¯æ¬¡ã®ããã«ãªããŸãã
class C {
member: number;
static member: string;
}
let instance = new C();
let result = getProperty<C, typeof instance.member>(instance, "member");
ãããŠã result
ã¯ã¿ã€ãnumber
ãæ£ããåãåããŸãã
ãã ããåŒã³åºãã«ã¯ãmemberããžã®éè€ããåç §ãããããã§ãã1ã€ã¯typeãã©ã¡ãŒã¿ãŒã«ããããã1ã€ã¯ã¿ãŒã²ããããããã£åã®æååè¡šçŸãåžžã«åãââåã_literal_æååã§ãã ãã®ææ¡ã®ã¢ã€ãã¢ã¯ãããã2ã€ããæååè¡šçŸã®ã¿ãåãåãåäžã®åãã©ã¡ãŒã¿ãŒã«çµ±åã§ãããšãããã®ã§ãã
ãããã£ãŠãããã§ã¯ãæååã_genericãã©ã¡ãŒã¿ãŒ_ãšããŠãæ©èœãããããæ©èœããããã«ãªãã©ã«ãšããŠæž¡ãããå¿ èŠãããããšã«æ³šæããå¿ èŠããããŸãïŒä»ã®å Žåã¯ãäœããã®åœ¢åŒã®ã©ã³ã¿ã€ã ãªãã¬ã¯ã·ã§ã³ã䜿çšå¯èœã§ãªãéãããã®å€ãé»ã£ãŠç¡èŠã§ããŸãïŒã ãããã£ãŠãã»ãã³ãã£ã¯ã¹ãæ確ã«ããããã«ãæ±çšãã©ã¡ãŒã¿ãŒãšæååã®éã®é¢ä¿ã瀺ãäœããã®æ¹æ³ãå¿ èŠã§ãã
function getProperty<T extends object, PName: string = propertyName>(container: T; propertyName: string) {
return <T[PName]> container[propertyName];
}
ãããŠä»ãåŒã³åºãã¯æ¬¡ã®ããã«ãªããŸãïŒ
let instance = new C();
let result = getProperty<C>(instance, "member");
ããã¯å éšçã«æ¬¡ã®ããã«è§£æ±ºãããŸãã
let result = getProperty<C, "member">(instance, "member");
ãã ãã C
ã¯member
ãšããååã®ã€ã³ã¹ã¿ã³ã¹ãšéçããããã£ã®äž¡æ¹ãå«ãŸããŠãããããããçš®é¡ã®å€ãäžè¬åŒT[PName]
ã¯ãããŸãã§ãã ããã§ã®æå³ã¯äž»ã«ã€ã³ã¹ã¿ã³ã¹ã®ããããã£ã«é©çšããããšã§ãããããææ¡ãããtypeon
æŒç®åã®ãããªãœãªã¥ãŒã·ã§ã³ãå
éšã§äœ¿çšã§ããŸããããã«ããã T[PName]
ã次ã®ããã«è§£éããããããã»ãã³ãã£ã¯ã¹ãæ¹åãããå¯èœæ§ããããŸãã _value reference_ãå¿
ãããã¿ã€ãã§ã¯ãããŸããïŒ
function getProperty<T extends object, PName: string = propertyName>(container: T; propertyName: string) {
return <typeon T[PName]> container[propertyName];
}
ïŒ typeon
ãã€ã³ã¿ãŒãã§ã€ã¹ããµããŒãããŠããããã T
ãäºææ§ã®ããã€ã³ã¿ãŒãã§ã€ã¹ã¿ã€ãã§ããå Žåã«ãæ©èœããŸãïŒ
éçããããã£ãååŸããã«ã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒèªäœã䜿çšããŠé¢æ°ãåŒã³åºããã³ã³ã¹ãã©ã¯ã¿ãŒã®åãtypeof C
ãšããŠæž¡ãå¿
èŠããããŸãã
let result = getProperty<typeof C>(C, "member"); // Note it is called with the constructor object
ïŒå
éšçã«typeon (typeof C)
ã¯typeof C
解決ããããããããã¯æ©èœããŸãïŒ
result
ã¯ãã¿ã€ãstring
æ£ããåãåãããã«ãªããŸããã
è¿œå ã®ã¿ã€ãã®ããããã£èå¥åããµããŒãããããã«ãããã¯æ¬¡ã®ããã«æžãçŽãããšãã§ããŸãã
type PropertyIdentifier = string|number|Symbol;
function getProperty<T extends object, PName: PropertyIdentifier = propertyName>(container: T; propertyName: PropertyIdentifier) {
return <typeon T[PName]> container[propertyName];
}
ãããã£ãŠãããããµããŒãããããã«å¿ èŠãªããã€ãã®ç°ãªãæ©èœããããŸãã
ããã§ã¯ãå ã®åé¿çã«æ»ããŸãããã
function getProperty<T extends object, P>(container: T; propertyName: string) {
return <P> container[propertyName];
}
ãã®åé¿çã®å©ç¹ã®1ã€ã¯ãçŽæ¥ããããã£ã ãã§ãªãããã¹ãããããªããžã§ã¯ãã®ããããã£ãåç §ããŠãããè€éãªãã¹åããµããŒãããããã«ç°¡åã«æ¡åŒµã§ããããšã§ãã
function getPath<T extends object, P>(container: T; path: string) {
... more complex code here ...
return <P> resultValue;
}
ãããŠä»ïŒ
class C {
a: {
b: {
c: string[];
}
}
}
let instance = new C();
let result = getPath<C, typeof instance.a.b.c>(instance, "a.b.c");
result
ã¯ãããã§ã¿ã€ãstring[]
ãæ£ããååŸããŸãã
åé¡ã¯ããã¹ãããããã¹ããµããŒãããå¿ èŠããããã©ããã§ãã å ¥åæã«ãªãŒãã³ã³ããªãŒããå©çšã§ããªãå Žåããã®æ©èœã¯æ¬åœã«äŸ¿å©ã§ããïŒ
ããã¯ãå¥ã®è§£æ±ºçãå¯èœã§ããããããä»ã®æ¹åã«æ©èœããå¯èœæ§ãããããšã瀺åããŠããŸãã å ã®åé¿çã«æ»ãïŒ
function getProperty<T extends object, P>(container: T; propertyName: string) {
return <P> container[propertyName];
}
ãããå¥ã®æ¹åããèŠããšãååç §èªäœãååŸããŠæååã«å€æããããšãã§ããŸãã
function getProperty<T extends object, P>(container: T; propertyName: string = @typeReferencePathOf(P)) {
return <P> container[propertyName];
}
@typeReferencePathOf
ã¯ãæŠå¿µçã«ã¯nameOf
䌌ãŠããŸãããæ±çšãã©ã¡ãŒã¿ãŒã«é©çšãããŸãã åä¿¡ããååç
§typeof instance.member
ïŒãŸãã¯typeon C.member
ïŒãåãåããããããã£ãã¹member
æœåºããã³ã³ãã€ã«æã«ãªãã©ã«æåå"member"
ã«å€æããŸããæéã ããŸãå°éåãããŠããªãè£å®çãª@typeReferenceOf
ã¯ãå®å
šãªæåå"typeof instance.member"
解決ãããŸãã
ã ããä»ïŒ
getProperty<C, typeof instance.subObject>(instance);
解決ããŸãïŒ
getProperty<C, typeof instance.subObject>(instance, "subObject");
ãããŠã getPath
åæ§ã®å®è£
ïŒ
getPath<C, typeof instance.a.b.c>(instance);
解決ããŸãïŒ
getPath<C, typeof instance.a.b.c>(instance, "a.b.c");
@typeReferencePathOf(P)
ã¯ããã©ã«ãå€ãšããŠã®ã¿èšå®ãããŠããããã åŒæ°ã¯ãå¿
èŠã«å¿ããŠæåã§æå®ã§ããŸãã
getPath<C, SomeTypeWhichIsNotAPath>(instance, "member.someSubMember.AnotherSubmember.data");
2çªç®ã®ã¿ã€ãã®ãã©ã¡ãŒã¿ãŒãæå®ãããªãå Žåã @typeReferencePathOf()
ã¯undefined
解決ããããã空ã®æåå""
ãŸãã ã¿ã€ããæäŸããããå
éšãã¹ããªãã£ãå Žåã ""
解決ãããŸãã
ãã®ã¢ãããŒãã®å©ç¹ïŒ
typeof
åŒãå
¥åãããšãã«ãªãŒãã³ã³ããªãŒããèš±å¯ããã³ã³ãã€ã«æã«æååè¡šçŸããå€æããå¿
èŠããªããåãã§ãã¯ã®æ¢åã®ã¡ã«ããºã ã䜿çšããŠæ€èšŒããŸããtypeon
ã¯å¿
èŠãããŸããïŒãã ãããµããŒãã§ããŸãïŒã+1
ãããïŒ ç§ã¯ãã§ã«åãåé¡ã«å¯ŸåŠããããã®å€§ããªææ¡ãæžãå§ããŸãããããã®è°è«ãèŠã€ããã®ã§ãããã§è°è«ããŸãããã
ãããç§ã®æªæåºã®åé¡ããã®æç²ã§ãïŒ
質åïŒæ¬¡ã®é¢æ°ã¯ã䜿çšãããããšã«ãªã£ãŠããã³ã³ããã¹ãã§äœ¿çšã§ããããã«ã.d.tsã§ã©ã®ããã«å®£èšããå¿ èŠããããŸããïŒ
function mapValues(obj, fn) {
return Object.keys(obj)
.map(key => ({key, value: fn(obj[key], key)}))
.reduce((res, {key, value}) => (res[key] = value, res), {})
}
ãã®é¢æ°ïŒããããªéãã¯ãããŸãïŒã¯ãã»ãšãã©ãã¹ãŠã®äžè¬çãªãutilsãã©ã€ãã©ãªã«ãããŸãã
éçã®mapValues
ã«ã¯2ã€ã®ç°ãªããŠãŒã¹ã±ãŒã¹ããããŸãã
aã _Object-as-a-_ _Dictionary _ããã§ãããããã£åã¯åçã§ãããå€ã¯åã1ã€ã®ã¿ã€ãã§ãããé¢æ°ã¯äžè¬ã«å圢ã§ãïŒãã®ã¿ã€ããèªèããŸãïŒ
var obj = {'a': 1, 'b': 2, 'c': 3};
var res = mapValues(x, val => val * 5); // {a: 5, b: 10, c: 15}
console.log(res['a']) // 5
bã _Object-as-a-_ _Record _ããã§ãåããããã£ã¯ç¬èªã®ã¿ã€ããæã¡ãé¢æ°ã¯ãã©ã¡ããªãã¯ã«å€æ çã§ãïŒå®è£ ã«ããïŒ
var obj = {a: 123, b: "Hello", c: true};
var res = mapValues(p, val => [val]); // {a: [123], b: ["Hello"], c: [true]}
console.log(res.a[0].toFixed(2)) // "123.00"
çŸåšã®TypeScriptã§mapValues
å©çšã§ããæè¯ã®ã€ã³ã¹ãã«ã¡ã³ããŒã·ã§ã³ã¯ã次ã®ãšããã§ãã
declare function mapValues<T1, T2>(
obj: {[key: string]: T1},
fn: (arg: T1, key: string) => T2
): {[key: string]: T2};
ãã®çœ²åã_Object-as-a -__ Dictionary _ãŠãŒã¹ã±ãŒã¹ã«å®å šã«äžèŽããããšã確èªããã®ã¯é£ãããããŸãããã_Object-as-a-_ã®å Žåã«é©çšãããšãåæšè«ã®çµæãããé©ãã¹ã1ã«ãªããŸãã _Record_ãæå³ãããŠããŸããã
ã¿ã€ã{p1: T1, p2: T2, ...pn: Tn}
ã¯ããã¹ãŠã®ã¿ã€ããçµ±åããã¬ã³ãŒãã®æ§é ã«é¢ãããã¹ãŠã®æ
å ±ãå¹æçã«ç Žæ£ãã{[key: string]: T1 | T2 | ... | Tn }
匷å¶å€æãããŸãã
console.log(res.a[0].toFixed(2))
ã¯ã³ã³ãã€ã©ã«ãã£ãŠæåŠãããŸããconsole.log((<number>res['a'][0]).toFixed(2))
ã¯ãåãã£ã¹ããšä»»æã®ããããã£åã®2ã€ã®å¶åŸ¡ãããŠããªããšã©ãŒãçºçããããå ŽæããããŸãã1ã2 âESããTSã«ç§»è¡ããããã°ã©ããŒåã
type Numbers<p extends string> = { ...p: number };
type NumbersOpt<p extends string> = {...p?: number };
type ABC = "a" | "b" | "c";
type abc = Numbers<ABC> // abc = {a: number, b: number, c: number}
type abcOpt = NumbersOpt<ABC> // abcOpt = {a?: number, b?:number, c?: number}
function toFixedAll<p extends string>(obj: {...p: number}, precision):{...p: string} {
var result: {...p: string} = {} as any;
Object.keys(obj).forEach((p:p) => {
result[p] = obj[p].toFixed(precision);
});
return result;
}
var test = toFixedAll({x:5, y:7}, 3); // { x: "5.00", y: "6.00" }, p inferred as "x"|"y"
console.log(test.y.length) // 4 test.y: string
äŸïŒ
declare function mapValues<p extends string, T1[p], T2[p]>(
obj:{...p: T1[p]}, fn:(arg: T1[p]) => T2[p]
): {...p: T2[p]};
äŸïŒ
class C<Array<T>> {
x: T;
}
var v1: C<string[]>; // v1.x: string
3ã€ã®ã¹ããããã¹ãŠãäžç·ã«æžãããšãã§ããŸã
declare module Backbone {
class Model<{...p: T[p]}> {
get(prop: p): T[p];
set(prop: p, value: T[p]): void;
}
}
declare module ImmutableJS {
class Map<{...p: T[p]}> {
get(prop: p): T[p];
set(prop: p, value: T[p]): this;
}
}
declare function pluck<p extends string, T[p]>(
arr: Array<{...p:T[p]}>, prop: p
): Array<T[p]>
æ§æã@fdecampredonã«ãã£ãŠææ¡ããããã®ãããåé·ã§ããããšãç§ã¯ç¥ã£ãŠããŸã
ããããå
ã®ææ¡ã§mapValues
ãŸãã¯combineReducers
ã®ã¿ã€ããè¡šçŸããæ¹æ³ãæ³åããããšã¯ã§ããŸããã
function combineReducers(reducers) {
return (state, action) => mapValues(reducers, (reducer, key) => reducer(state[key], action))
}
ç§ã®ææ¡ã§ã¯ããã®å®£èšã¯æ¬¡ã®ããã«ãªããŸãã
declare function combineReducers<p extends string, S[p]>(
reducers: { ...p: (state: S[p], action: Action) => S[p] }
): (state: { ...p: S[p] }, action: Action) => { ...p: S[p] };
å ã®ææ¡ã§è¡šçŸã§ããŸããïŒ
@ spion ã @ fdecampredon ïŒ
@Artazorééããªãæ¹åã ããã§ããã®æ©èœã®ãã³ãããŒã¯ãŠãŒã¹ã±ãŒã¹ãè¡šçŸããã®ã«ååãªããã§ãã
user.id
ãšuser.name
ããããã«å¿ããŠnumber
ãšstring
ãå«ãããŒã¿ããŒã¹åã¿ã€ãã§ãããšä»®å®ããŸããã€ãŸãColumn<number>
ãšColumn<string>
次ã®é¢æ°select
ã®ã¿ã€ããèšè¿°ããŸãã
select({id: user.id, name: user.name})
ãããŠQuery<{id: number; name: string}>
ãè¿ããŸã
select<T>({...p: Column<T[p]>}):Query<T>
ãããããããã©ã®ããã«ãã§ãã¯ãããæšæž¬ãããã®ãã¯ããããŸããã ã¿ã€ãTãååšããªããããåé¡ãããããã§ãã æ»ãå€ã®åã¯ãéæ§é åããã圢åŒã§è¡šçŸããå¿ èŠããããŸããïŒ ããªãã¡
select<T>({...p: Column<T[p]>}):Query<{...p:T[p]}>
@Artazorã¯è³ªåããã®ãå¿ããŸããã p extends string
ãã©ã¡ãŒã¿ã¯æ¬åœã«å¿
èŠã§ããïŒ
ãã®ãããªãã®ã§ååã§ã¯ãªãã§ããããïŒ
select<T[p]>({...p: Column<T[p]>}):Query<{...p:T[p]}>
ã€ãŸãã {...p:Column<T[p]>}
ãã¹ãŠã®åå€æ°T [p]
ç·šéïŒå¥ã®è³ªåãããã¯ã©ã®ããã«æ£ãããã©ããããã§ãã¯ããã®ã§ããïŒ
@spionç§ã¯ããªãã®èŠè§£ãæã£ãŠããŸãâããªãã¯ç§ã誀解ããŸããïŒãããããã¯ç§ã®ããã§ãïŒã T[p]
ç§ã¯ãŸã£ããç°ãªãããšãæå³ããŸããããããŠããªãã¯ãã®p extends string
ãèŠãã§ããã
ããŒã¿æ§é ã®4ã€ã®ãŠãŒã¹ã±ãŒã¹ãèããŠã¿ãŸãããïŒ List
ã Tuple
ã Dictionary
ã Record
ã ãããã_æŠå¿µããŒã¿æ§é _ãšåŒã³ã次ã®ããããã£ã§èª¬æããŸãã
æŠå¿µçãªããŒã¿æ§é | ã«ããã¢ã¯ã»ã¹ | ||
---|---|---|---|
aã ããžã·ã§ã³ ïŒæ°ïŒ | bã ã㌠ïŒã¹ããªã³ã°ïŒ | ||
ã®æ° ã¢ã€ãã | 1.å€æ° ïŒåã¢ã€ãã ã§åã圹å²ïŒ | ãªã¹ã | èŸæž |
2.ä¿®æ£æžã¿ ïŒåã¢ã€ãã ã¯ç¬èªã®åœ¹å²ãæãããŸãïŒ | ã¿ãã« | èšé² |
JavaScriptã§ã¯ãããã4ã€ã®ã±ãŒã¹ã¯2ã€ã®ã¹ãã¬ãŒãžåœ¢åŒã«ãã£ãŠæ¯ããããŠããŸããa1ãša2ã®å Žåã¯Array
ã b1ãšb2ã®å Žåã¯Object
ã§ãã
_泚1_ ã æ£çŽãªãšããã
Tuple
ãArray
ã«æ¯ããããŠãããšèšãã®ã¯æ£ãããããŸãããããã¯ãå¯äžã®ãçã®ãã¿ãã«åãarguments
ãªããžã§ã¯ãã®åã§ããããã§ããArray
ã¯ãããŸããã ããã«ããããããããããã¯å€ããå°ãªããäºææ§ããããç¹ã«ç Žå£ãšã¡ã¿ããã°ã©ãã³ã°ãžã®æãéãFunction.prototype.apply
ã®ã³ã³ããã¹ãã§ã¯ããã§ãã TypeScriptã¯ãã¿ãã«ã®ã¢ããªã³ã°ã«é åã掻çšããŸãã_泚2_ã ä»»æã®ããŒãæã€èŸæžã®å®å šãªæŠå¿µã¯ãæ°å幎åŸã«ES6
Map
圢ã§å°å ¥ãããŸããããRecord
ãšéå®ãããDictionary
ãçµ±åãããšããBrendanEichã®æåã®æ±ºå®ïŒæååããŒã®ã¿ïŒObject
ïŒobj.prop
ã¯obj["prop"]
ãšåçïŒã®åãããŒãã®äžã§ãèšèªå šäœã®äžã§æãç©è°ãéžãèŠçŽ ã«ãªããŸããïŒç§ã®æèŠã§ã¯ïŒã
ããã¯ãJavaScriptã»ãã³ãã£ã¯ã¹ã®åªããšç¥çŠã®äž¡æ¹ã§ãã ããã¯å çãäºçŽ°ãªãã®ã«ããããã°ã©ããŒãïŒæ°ã¥ããªããŠãïŒïŒã»ãšãã©ãŒãã®ç²Ÿç¥çã³ã¹ãã§_programming_ã¬ãã«ãš_meta-programming_ã¬ãã«ãèªç±ã«åãæ¿ããããšã奚å±ããŸãã ã¹ã¯ãªããèšèªãšããŠã®JavaScriptã®æåã«æ¬ ãããªãèŠçŽ ã ãšæããŸãã
ä»ãããTypeScriptããã®å¥åŠãªã»ãã³ãã£ã¯ã¹ã®åãè¡šçŸããæ¹æ³ãæäŸããæã§ãã _ããã°ã©ãã³ã°_ã¬ãã«ã§èãããšããã¹ãŠåé¡ãããŸããã
ããã°ã©ãã³ã°ã¬ãã«ã§ã®å | ã«ããã¢ã¯ã»ã¹ | ||
---|---|---|---|
aã ããžã·ã§ã³ ïŒæ°ïŒ | bã ã㌠ïŒã¹ããªã³ã°ïŒ | ||
ã®æ° ã¢ã€ãã | 1.å€æ° ïŒåã¢ã€ãã ã§åã圹å²ïŒ | T [] | {[ããŒïŒæåå]ïŒT} |
2.ä¿®æ£æžã¿ ïŒåã¢ã€ãã ã¯ç¬èªã®åœ¹å²ãæãããŸãïŒ | [T1ãT2ã...] | {key1ïŒT1ãkey2ïŒT2ã...} |
ãã ãã_meta-programming_ã¬ãã«ã«åãæ¿ãããšã_programming_ã¬ãã«ã§ä¿®æ£ããããã®ãçªç¶å¯å€ã«ãªããŸãã ãããŠããã§ãã¿ãã«ãšé¢æ°ã·ã°ããã£ã®é¢ä¿ãçªç¶èªèããïŒ5453ïŒVariadic KindsïŒã®ãããªãã®ãææ¡ããŸããããã¯ãå®éã«ã¯ã¡ã¿ããã°ã©ãã³ã°ã®ããŒãºã®ããäžéšïŒãã ãéåžžã«éèŠïŒã®ã¿ãã«ããŒããŸããæ®ãã®åŒæ°ã®ã¿ã€ããžã®ãã©ã¡ãŒã¿ãŒïŒ
function f<T>(a: number, ...args:T) { ... }
f<[string,boolean]>(1, "A", true);
ïŒ6018ãå®è£ ãããå ŽåãFunctionã¯ã©ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
declare class Function<This, TArgs, TRes> {
This::(...args: TArgs): TRes;
call(self: This, ...args: TArgs): TRes;
apply(self: This, args: TArgs): TRes;
// bind needs also formal pattern matching:
bind<[...TPartial, ...TCurried] = TArgs>(
self: This, ...args: TPartial): Function<{}, TCurried, TRes>
}
ããã¯çŽ æŽãããã§ããããšã«ããäžå®å šã§ãã
ããšãã°ã次ã®é¢æ°ã«æ£ããåãå²ãåœãŠãããšããŸãã
function extractAndWrapAll(...args) {
return args.map(x => [x]);
}
// wrapAll(1,"A",true) === [[1],["A"],[true]]
ææ¡ãããå¯å€ååŒæ°ã®çš®é¡ã§ã¯ã眲åã®çš®é¡ãå€æã§ããŸããã ããã§ã¯ããã£ãšåŒ·åãªãã®ãå¿ èŠã§ãã å®éãïŒFacebookã®ãããŒã®ããã«ïŒåãæäœã§ããã³ã³ãã€ã«æé¢æ°ãããããšãæãŸããã§ãã ãã ããããã¯ãTypeScriptã®åã·ã¹ãã ãã次ã®ãã€ããŒã¢ããããŒãã§ãŠãŒã¶ãŒã©ã³ããå£ã倧ããªãªã¹ã¯ãªãã«ãšã³ãããã°ã©ããŒã«å ¬éããã®ã«ååå®å®ããŠããå Žåã«ã®ã¿å¯èœã«ãªããšç¢ºä¿¡ããŠããŸãã ãããã£ãŠãå®å šãªã¡ã¿ããã°ã©ãã³ã°ãµããŒããããéæ¿ã§ã¯ãªããã®ã®ãå®èšŒãããåé¡ã«å¯ŸåŠã§ãããã®ãå¿ èŠã§ãã
ãã®åé¡ã«å¯ŸåŠããããã«ã_objectsignature_ã®æŠå¿µã玹ä»ããããšæããŸãã 倧ãŸãã«ã©ã¡ããã§ã
çæ³çã«ã¯ã次ã®ãããªé åãŸãã¯ã¿ãã«ã®ã·ã°ããã£ãè¡šãããã«ãæŽæ°ãªãã©ã«ã¿ã€ããšæååãªãã©ã«ã¿ã€ãããããšäŸ¿å©ã§ãã
type ZeroToFive = 0 | 1 | 2 | 3 | 4 | 5;
// or
type ZeroToFive = 0 .. 5; // ZeroToFive extends number (!)
æŽæ°ãªãã©ã«ã®èŠåã¯ãæååãªãã©ã«ã®èŠåãšäžèŽããŠããŸãã
次ã«ããªããžã§ã¯ãã®ã¬ã¹ã/ã¹ãã¬ããæ§æãšå®å šã«äžèŽãã眲åæœè±¡åæ§æãå°å ¥ã§ããŸãã
{...Props: T }
1ã€ã®éèŠãªäŸå€ãé€ããŠãããã§Props
ã¯ãå
šç§°èšå·ã®äžã§ãã€ã³ããããèå¥åã§ãã
<Props extends string> {...Props: T } // every property has type T
<Index extends number> {...Index: T } // every item has type T
// the same as T[]
ãããã£ãŠãã¿ã€ãã¬ãã·ã«ã«ã¹ã³ãŒãã§å°å ¥ãããã¿ã€ãã®ååãšããŠãã®ã¹ã³ãŒãå ã®ã©ãã§ã䜿çšã§ããŸãã ãã ãããã®äœ¿çšæ³ã¯äºéã§ããrest/ Spreadããããã£åã®ä»£ããã«äœ¿çšãããšããªããžã§ã¯ãã·ã°ããã£ã®æœè±¡åãè¡šããã¹ã¿ã³ãã¢ãã³ã¿ã€ãã䜿çšãããšãæååïŒãŸãã¯æ°å€ïŒã®ãµãã¿ã€ããè¡šããŸãã
declare class Object {
static keys<p extends string, q extends p>(object{...q: {}}): p[];
}
ãããŠããããæãæŽç·Žãããéšåã§ãïŒ_ããŒäŸåå_
ç¹å¥ãªåæ§é ã玹ä»ããŸãïŒ T for Prop
ïŒæ··ä¹±ããT [Prop]ã§ã¯ãªããã®æ§æã䜿çšãããïŒããã§ãPropã¯ãªããžã§ã¯ãã®çœ²åã®æœè±¡åãä¿æããåå€æ°ã®ååã§ãã äŸãã°<Prop extends string, T for Prop>
çºè¡šã¿ã€ãåå¥ç¯å²ã«2ã€ã®ä»®ã¿ã€ãã Prop
ããã³T
ããã¯ãåç¹å®ã®å€ã®ããã«ç¥ãããŠããå Žåp
ã®Prop
ç¬èªã®ã¿ã€ãT
ãŸãã
ããããã£ã
Props
ããã®ã¿ã€ããT
ãããªããžã§ã¯ããã©ããã«ãããšã¯èšããŸããïŒ 2ã€ã®ã¿ã€ãéã®æ©èœäŸåæ§ã®ã¿ã玹ä»ããŸãã ã¿ã€ãTã¯ã¿ã€ãããããã®ã¡ã³ããŒãšçžé¢é¢ä¿ããããããã ãã§ãïŒ
ããã¯ç§ãã¡ã«ãã®ãããªãã®ãæžãå¯èœæ§ãäžããŸã
function unwrap<P extends string, T for P>(obj:{...P: Maybe<T>}): Maybe<{...P: T}> {
...
}
unwrap({a:{value:1}, b:{value:"A"}, c:{value: true}}) === { a: 1, b: "A", c: true }
// here actual parameters will be inferred as
unwrap<"a"|"b"|"c", {a: number, b: string, c: boolean}>
ãã ãã2çªç®ã®ãã©ã¡ãŒã¿ãŒã¯ãªããžã§ã¯ããšããŠã§ã¯ãªããã¿ã€ããžã®èå¥åã®æœè±¡çãªããããšããŠæ±ãããŸãã ãã®èŠ³ç¹ã§ã¯ãPãæ°å€ã®ãµãã¿ã€ãã§ããå Žåã T for P
ã䜿çšããŠãã¿ãã«ã®ã¿ã€ãã®æœè±¡ã·ãŒã±ã³ã¹ãè¡šãããšãã§ããŸãïŒ @JsonFreeman ïŒïŒ
T
ã{...P: .... T .... }
å
ã®ã©ããã§äœ¿çšãããŠããå Žåãããã¯ãã®ãããã®1ã€ã®ç¹å®ã®ã¿ã€ããè¡šããŸãã
ãããç§ã®äž»ãªã¢ã€ãã¢ã§ãã
質åãèããæ¹å€ãç±å¿ã«åŸ
ã£ãŠããŸã-ïŒ
ããã§ãã extends string
ã¯ãããå Žåã«ã¯é
åïŒããã³å¯å€ååŒæ°ïŒãèæ
®ã«å
¥ããä»ã®å Žåã«ã¯ïŒåãšããŠã®ïŒæååå®æ°ãèæ
®ã«å
¥ããããšã§ãã çãïŒ
ã©ããã«ããããã£Propsãæã€ãªããžã§ã¯ããããããã®ã¿ã€ããTã§ãããšã¯èšããŸããã 2ã€ã®ã¿ã€ãéã®æ©èœäŸåæ§ã®ã¿ã玹ä»ããŸãã ã¿ã€ãTã¯ã¿ã€ãããããã®ã¡ã³ããŒãšçžé¢é¢ä¿ããããããã ãã§ãïŒ
ç§ã¯ãããæå³ããŠããŸããã§ããããããã®ã¿ã€ãã¯T [p]ã§ãããpã§ã€ã³ããã¯ã¹ä»ããããã¿ã€ãã®èŸæžã§ããããã§ãã ãããè¯ãçŽæãªããç§ã¯ãããç¶æããŸãã
å šäœçã«èŠãŠãæ§æã«ã¯ããå°ãäœæ¥ãå¿ èŠãããããŸããããäžè¬çãªèãæ¹ã¯çŽ æŽãããããã«èŠããŸãã
å¯å€ååŒæ°ã«unwrap
ãæžãããšã¯å¯èœã§ããïŒ
ç·šéïŒæ°ã«ããªãã§ãã ãããç§ã¯ããªããææ¡ããå¯å€ååŒæ°ã®çš®é¡ãžã®æ¡åŒµãããã«å¯ŸåŠããŠããããšã«æ°ã¥ããŸããã
ã¿ãªãããããã«ã¡ã¯ã
ç§ã¯èªåã®åé¡ã®1ã€ã解決ããæ¹æ³ã«æžæãããã®è°è«ãèŠã€ããŸããã
åé¡ã¯ïŒ
RpcManager.call(command:Command):Promise<T>
ã¡ãœãããããã䜿çšæ³ã¯æ¬¡ã®ããã«ãªããŸãã
RpcManager.call(new GetBalance(123)).then((result) => {
// here I want that result would have a type.
});
ç§ãæã解決çã¯æ¬¡ã®ããã«ãªããŸãïŒ
interface Command<T> {
responseType:T;
}
class GetBalance implements Command<number> {
responseType: number; // somehow this should be avoided. maybe Command should be abstract class.
constructor(userId:number) {}
}
class RpcManager {
static call(command:Command):Promise<typeof command.responseType> {
}
}
or:
class RpcManager {
static call<T>(command:Command<T>):Promise<T> {
}
}
ããã«ã€ããŠäœãèãã¯ãããŸããïŒ
@ antanas-arvaseviciusãã®äŸã®æåŸã®ã³ãŒããããã¯ã¯ãããªããæãããšãããã¯ãã§ãã
ç¹å®ã®ã¿ã¹ã¯ãã©ã®ããã«å®è¡ãããã«ã€ããŠããã£ãšçåãããããã§ãã ã³ã³ãã€ã©ã®ãã°ãèŠã€ãããšæãããå Žåã¯ãStack Overflowã䜿çšããããåé¡ãå ±åããŠãã ããã
ããã«ã¡ã¯ãã©ã€ã¢ã³ããè¿äºããããšãããããŸãã
ã³ãŒãã®æåŸã®ãããã¯ãè©ŠããŸããããæ©èœããŸããã
ã¯ã€ãã¯ãã¢ïŒ
interface Command<T> { }
class MyCommand implements Command<{status:string}> { }
class RPC { static call<T>(command:Command<T>):T { return; } }
let response = RPC.call(new MyCommand());
console.log(response.status);
//output: error TS2339: Property 'status' does not exist on type '{}'.
//tested with: Version 1.9.0-dev.20160222
Stack Overflowã䜿çšããªãã£ãã®ã¯æ®å¿µã§ããããã®åé¡ã«é¢é£ããŠãããšæããŸãã:)
ãã®ãããã¯ã«é¢ããæ°ããåé¡ãéãå¿
èŠããããŸããïŒ
æ¶è²»ãããŠããªããžã§ããªãã¯åãã©ã¡ãŒã¿ãŒã¯ãæšè«ãæ©èœããªãããã«ããŸãã äžè¬ã«ãå宣èšã«æªäœ¿çšã®åãã©ã¡ãŒã¿ãŒã¯æå³ããªãããã絶察ã«äœ¿çšããªãã§ãã ããã T
ãæ¶è²»ãããšããã¹ãŠãæ£åžžã«æ©èœããŸãã
interface Command<T> { foo: T }
class MyCommand implements Command<{status:string}> { foo: { status: string; } }
class RPC { static call<T>(command:Command<T>):T { return; } }
let response = RPC.call(new MyCommand());
console.log(response.status);
ããã¯ãããïŒ ããããšãããããŸããïŒ
åãã©ã¡ãŒã¿ãŒããžã§ããªãã¯åã®äžã«é
眮ã§ãããšã¯æã£ãŠããŸããã§ããã
TSããããæœåºããŸãã
2016幎2æ22æ¥ååŸ11æ56åããRyanCavanaughã [email protected]ã¯æ¬¡ã®ããã«æžããŠããŸãã
æ¶è²»ãããŠããªããžã§ããªãã¯åãã©ã¡ãŒã¿ãŒã¯ãæšè«ãæ©èœããªãããã«ããŸãã ã«
äžè¬çã«ãåã«æªäœ¿çšã®åãã©ã¡ãŒã¿ãå«ããã¹ãã§ã¯ãããŸããã
圌ãã¯ç¡æå³ãªã®ã§å®£èšã Tãæ¶è²»ãããšããã¹ãŠã
äœåïŒã€ã³ã¿ãŒãã§ã€ã¹ã³ãã³ã
{fooïŒT} classMyCommandã¯Command <{statusïŒstring}>ãå®è£ ããŸã{fooïŒ{statusïŒstring; }} class RPC {éçåŒã³åºã ïŒã³ãã³ãïŒã³ãã³ã ïŒïŒT {return; }}
å¿ç= RPC.callïŒnew MyCommandïŒïŒïŒ;
console.logïŒresponse.statusïŒ;â
ãã®ã¡ãŒã«ã«çŽæ¥è¿ä¿¡ããããGitHubã§è¡šç€ºããŠãã ãã
https://github.com/Microsoft/TypeScript/issues/1295#issuecomment -187404245
ã
@ antanas-arvasevicius RPCã¹ã¿ã€ã«ã®APIãäœæããŠããå Žåã圹ç«ã€ãšæãããããã¥ã¡ã³ããããã€ããããŸãïŒ https ïŒ
äžèšã®ã¢ãããŒãã¯æ¬¡ã®ããã§ãã
string
ã¯ãããã¹ãŠã®åç
§ãæ€çŽ¢ãããããšãããªãã¡ã¯ã¿ãªã³ã°ããããšãã§ããŸããïŒååã®å€æŽãªã©ïŒãããã¯ãCïŒåŒããªãŒã«è§Šçºãããå¥ã®ã¢ã€ãã¢ã§ãã ããã¯å€§ãŸããªã¢ã€ãã¢ã§ãããå®å šã«èãæããããã®ã§ã¯ãããŸããã æ§æã¯ã²ã©ãã§ãã ããã誰ããåºæ¿ãããã©ãããèŠããã ãã§ãã
åŒãè¡šãç¹å¥ãªçš®é¡ã®æååããããšããŸãã
ãããtype Expr<T, U> = string
ãšåŒã³ãŸãããã
ããã§ã T
ã¯éå§ãªããžã§ã¯ãã¿ã€ãã§ããã U
ã¯çµæã¿ã€ãã§ãã
ã¿ã€ãT
1ã€ã®ãã©ã¡ãŒã¿ãŒãåãåãããã®ãã©ã¡ãŒã¿ãŒã«å¯ŸããŠã¡ã³ããŒã¢ã¯ã»ã¹ãå®è¡ããã©ã ãã䜿çšããŠã Expr<T,U>
ã€ã³ã¹ã¿ã³ã¹ãäœæã§ãããšä»®å®ããŸãã
äŸïŒ person => person.address.city
ã
ãããçºçãããšãã©ã ãå
šäœãããã©ã¡ãŒã¿ãŒãžã®ã¢ã¯ã»ã¹ãå«ãŸããŠããæååïŒãã®å Žåã¯"address.city"
ïŒã«ã³ã³ãã€ã«ãããŸãã
代ããã«ãã¬ãŒã³ãªæååã䜿çšã§ããŸããããã¯Expr<any, any>
ãŸãã
ãã®ç¹å¥ãªExpr
ã¿ã€ããèšèªã«å«ãããšã次ã®ãããªããšãå¯èœã«ãªããŸãã
function pluck<T, U>(array: T[], prop: Expr<T, U>): U[];
let numbers = pluck([{x: 1}, {x: 2}], p => p.x); // number[]
// compiles to:
// let numbers = pluck([..], "x");
ããã¯åºæ¬çã«ãCïŒã§åŒã䜿çšãããç®çã®éå®ããã圢åŒã§ãã
ãããæŽç·ŽããŠãã©ããé¢çœããšããã«å°ãããšãã§ãããšæããŸããïŒ
@fdecampredon @RyanCavanaugh
_ïŒ @ jods4-ç³ãèš³ãããŸããããããã§ããªãã®ææ¡ã«è¿ä¿¡ããŠããŸãããã³ã¡ã³ãã§ãåãããŠãããªãããšãé¡ã£ãŠããŸãïŒ_
ãã®æ©èœã®ååïŒãã¿ã€ãããããã£ã¿ã€ããïŒã¯éåžžã«ãããã«ãããç解ããã®ãéåžžã«é£ãããšæããŸãã ããã§èª¬æãããŠããæŠå¿µãäœã§ãããããããããããäœãæå³ããã®ããç解ããããšããå°é£ã§ããã
ãŸãããã¹ãŠã®ã¿ã€ãã«ããããã£ãããããã§ã¯ãããŸããã undefined
ãšnull
ã¯ããã§ã¯ãããŸããïŒãããã¯åã·ã¹ãã ãžã®æè¿ã®è¿œå ã«ãããŸãããïŒã number
ã string
ã boolean
ãããªããªããã£ãã¯ãããããã£ã«ãã£ãŠã€ã³ããã¯ã¹ä»ããããããšã¯ãã£ãã«ãããŸããïŒããšãã°ã2 ["prop"]ïŒããã¯æ©èœããŠããããã«èŠããŸãããã»ãšãã©ã®å Žåééãã§ãïŒ
æååãªãã©ã«å€ã䜿çšããŠããã®åé¡ã®ãŸãã ããã§ã®ãããã¯ã¯ãæ°ãããã¿ã€ããã®å°å ¥ã«é¢ãããã®ã§ã¯ãªããæååå€æ°ãŸãã¯é¢æ°ãã©ã¡ãŒã¿ãŒã䜿çšããŠæ¢åã®ã¿ã€ããåç §ããéåžžã«ç¹æ®ãªæ¹æ³ã§ãããå€ã¯ã³ã³ãã€ã«æã«èªèãããŠããå¿ èŠããããŸãã
ç¹å®ã®ãŠãŒã¹ã±ãŒã¹ã®ã³ã³ããã¹ãã®å€ã§ããããã§ããã ãç°¡åã«èª¬æããã³äŸç€ºãããŠããã°ãéåžžã«æçã§ããã
interface MyInterface {
prop1: number;
prop2: string;
}
let prop1Name = "prop1";
type Prop1Type = MyInterface[prop1Name]; // Prop1Type is now 'number'
let prop2Name = "prop2";
type Prop2Type = MyInterface[prop2Name]; // Prop2Type is now 'string'
let prop3Name = "prop3";
type NonExistingPropType = MyInterface[prop3Name]; // Compilation error: property 'prop3' does not exist on 'MyInterface'.
let randomString = createRandomString();
type NotAvailablePropType = MyInterface[randomString]; // Compilation error: value of 'randomString' is not known at compile time.
_EditïŒãããæ£ããå®è£ ããã«ã¯ãã³ã³ãã€ã©ã¯ãå€æ°ã«å²ãåœãŠãããæååããåæåããããã€ã³ããšååŒã§åç §ããããã€ã³ãã®éã§å€æŽãããŠãå¿ èŠãããããã§ãã ããã¯ãšãŠãç°¡åã§ã¯ãªããšæããŸããïŒ å®è¡æã®åäœã«é¢ãããã®ä»®å®ã¯åžžã«æãç«ã¡ãŸããïŒ_
_ç·šé2ïŒããããããã¯å€æ°ãšäžç·ã«äœ¿çšããå Žåã«const
ã®ã¿æ©èœããŸããïŒ_
æååãªãã©ã«ãé¢æ°ãŸãã¯ã¡ãœããã®ãã©ã¡ãŒã¿ã«æž¡ããããšããéåžžã«ç¹æ®ãªã±ãŒã¹ã§ã®ã¿ããããã£åç §ãèš±å¯ããããšãæ¬æ¥ã®æå³ã§ãã£ããã©ããã¯ããããŸãããïŒ äŸãã°
function func(someString: string): MyInterface[someString] {
..
}
let x = func("prop"); // x gets the type of MyInterface.prop
ç§ã¯ãããåœåã®æå³ãè¶ ããŠäžè¬åããŸãããïŒ
é¢æ°ã®åŒæ°ãæååãªãã©ã«ã§ã¯ãªãå Žåãã€ãŸãã³ã³ãã€ã«æã«äžæãªå Žåãããã¯ã©ã®ããã«åŠçãããŸããïŒ äŸãã°
let x = func(getRandomString()); // What type if inferred for 'x' here?
ãšã©ãŒã«ãªããŸããããããšãããã©ã«ãã§any
ãŸããïŒ
ïŒè¿œèšïŒãããæ¬åœã«æå³ãããŠããå Žåã¯ããã®åé¡ã®ååãæååãªãã©ã«é¢æ°ãŸãã¯ã¡ãœããåŒæ°ã«ããã€ã³ã¿ãŒãã§ã€ã¹ããããã£ã¿ã€ãåç §ã«å€æŽããããšããå§ãã
ããã¯ããã®æ©èœãæå¹ã«ããããã«å¿ èŠãªãã®ã瀺ãç°¡åãªãã³ãããŒã¯ã®äŸïŒèª¬æã«ã¯ååã§ãïŒã§ãã
ãã®é¢æ°ã®ã¿ã€ããèšè¿°ããŸããããã¯æ¬¡ã®ãšããã§ãã
function awaitObject(obj) {
var result = {};
var wait = Object.keys(obj)
.map(key => obj[key].then(val => result[key] = val));
return Promise.all(wait).then(_ => result)
}
次ã®ãªããžã§ã¯ãã§åŒã³åºãããå ŽåïŒ
var res = awaitObject({a: Promise.resolve(5), b: Promise.resolve("5")})
çµæres
ã¯ã¿ã€ã{a: number; b: string}
å¿
èŠããããŸã
ãã®æ©èœïŒ@Artazorã«ãã£ãŠå®å šã«å ·äœåãããŠããïŒã䜿çšãããšã眲åã¯æ¬¡ã®ããã«ãªããŸãã
awaitObject<p, T[p]>(obj: {...p: Promise<T[p]>}):Promise<{...p: T[p]}>
ç·šéïŒäžèšã®æ»ãå€ã®åãä¿®æ£ããŸããã Promise<...>
ããããŸãã
@spion
äŸãæäŸããŠããã ãããããšãããããŸãããããã§ã¯ãåççã§ç°¡æœãªä»æ§ãšãå®éã®ã¢ããªã±ãŒã·ã§ã³ãã_åãé¢ããã_äžé£ã®æ確ãªçž®å°äŸãèŠã€ãããããã©ã®ããã«æ©èœãããã«ã€ããŠã®ã»ãã³ãã£ã¯ã¹ãšããŸããŸãªãšããžã±ãŒã¹ã匷調ããããšããŠããŸãã次ã®ãããªåºæ¬çãªãã®ã§ãïŒ
function func<T extends object>(name: string): T[name] {
...
}
name
ãã³ã³ãã€ã«æã«äžæãnullããŸãã¯æªå®çŸ©ã®å Žåãããšãã°func<MyType>(getRandomString())
ã func<MyType>(undefined)
å Žåãã©ããªããã«ã€ããŠæ確ãªèšåã¯ãããŸãããT
ãnumber
ãnull
ãããªããªããã£ãåã§ããå Žåã«äœãèµ·ãããã«ã€ããŠã®æ確ãªèšåã¯ãããŸããT[name]
ãé¢æ°æ¬äœã§äœ¿çšã§ãããã©ããã«ã€ããŠã®æ確ãªè©³çŽ°ã¯æäŸãããŠããŸããã ãã®å Žåã name
ãé¢æ°æ¬äœã§åå²ãåœãŠãããã³ã³ãã€ã«æã«ãã®å€ãããããªããªã£ãå Žåã¯ã©ããªããŸããïŒT["propName"]
ãŸãã¯T[propName]
ãããèªäœã§ãæ©èœããŸããïŒ ãã©ã¡ãŒã¿ãå€æ°ãžã®åç
§ããªããã°ãã€ãŸãã䟿å©ãããããŸããïŒT[name]
ãä»ã®ãã©ã¡ãŒã¿ãŒã§äœ¿çšã§ããå ŽåããŸãã¯é¢æ°ã¹ã³ãŒãã®å€ã§äœ¿çšã§ããå Žåã¯ãèšåãè°è«ããããŸãããfunction func<T extends object>(name: string, val: T[name]) {
...
}
type A = { abcd: number };
const name = "abcd";
let x: A[name]; // Type of 'x' resolves to 'number'
_7ã è¿œå ã®æ±çšãã©ã¡ãŒã¿ãŒãštypeof
ã䜿çšããæ¯èŒçåçŽãªåé¿çã«ã€ããŠã®å®éã®è°è«ã¯ãããŸããïŒèšåãããŸããããæ©èœããã§ã«åãå
¥ããããŠããæ¯èŒçé
ããŠããŸãïŒã
function get<T, V>(obj: T, propName: string): V {
return obj[propName];
}
type MyType = { abcd: number };
let x: MyType = { abcd: 12 };
let result = get<MyType, typeof x.abcd>(x, "abcd"); // Type of 'result' is 'number'
çµè«ïŒããã«ã¯å®éã®ææ¡ã¯ãªããäžé£ã®ãŠãŒã¹ã±ãŒã¹ã®ãã¢ã³ã¹ãã¬ãŒã·ã§ã³ã®ã¿ããããŸãã ãããTypeScriptããŒã ã«ãã£ãŠåãå ¥ããããããã«ã¯ååããªé¢å¿ãéããããšã«é©ããŠããŸããããã§ãªããã°ãããã圌ãã®åºæºã«éãããšã¯æããªãããã§ãã ããã§å°ãå³ããèããããããããŸãããïŒç§ã®å žåã§ã¯ãããŸããïŒãç³ãèš³ãããŸããããç§ã®æ¹å€ã¯å人çãªãã®ã§ããç¹å®ã®å人ã«åãããããã®ã§ããããŸããã
ã¡ã¿ããã°ã©ãã³ã°ã®èŠ³ç¹ãããæ¬åœã«ãããŸã§è¡ãããã§ããïŒ
JSã¯åçèšèªã§ãããã³ãŒãã¯ä»»æã®æ¹æ³ã§ãªããžã§ã¯ããæäœã§ããŸãã
åã·ã¹ãã ã§ã¢ãã«åã§ãããã®ã«ã¯éçããããTSã§ã¯ã¢ãã«åã§ããªãé¢æ°ãç°¡åã«æãä»ãããšãã§ããŸãã
åé¡ã¯ããããã©ããŸã§è¡ãããšãåççã§æçšããšããããšã§ãã
@spionã®æåŸã®äŸïŒ awaitObject
ïŒã¯åæã«ïŒ
ãšããã§@spionããªãã¯ããªãã®äŸã®æ»ãå€ã®åãæ£ããååŸããŸããã§ãã...ããã¯Promise
è¿ããŸãã
_.pluck
ãªã©ã®ãã£ãŒã«ããè¡šãæååãåãåãAPIã®å
¥åã«é¢ããå
ã®åé¡ãšã¯ããé¢ããŠããŸãã
ãããã®APIã¯äžè¬çã§ãããããã»ã©è€éã§ã¯ãªãããããµããŒãããå¿
èŠããããŸãã ãã®ããã«{ ...p: T[p] }
ãããªã¡ã¿ã¢ãã«ã¯å¿
èŠãããŸããã
OPã«ã¯ããã€ãã®äŸããããŸãããåé¡ã®ååã®ç§ã®ã³ã¡ã³ãã«ã¯Aureliaããã®äŸãããã€ããããŸãã
å¥ã®ã¢ãããŒãã§ãããã®ãŠãŒã¹ã±ãŒã¹ãã«ããŒã§ããŸããèããããã¢ã€ãã¢ã«ã€ããŠã¯ãäžèšã®ç§ã®ã³ã¡ã³ããåç
§ã
@ jods4ããã¯ãŸã£ããçããããŸããã çŸæç¹ã§ã¯åã·ã¹ãã ã§ã¢ãã«åããããšãäžå¯èœãªå€ãã®ããšã«äœ¿çšã§ããŸãã TSåã·ã¹ãã ã§æåŸã«æ¬ ããŠãã倧ããªéšåã®1ã€ã ãšæããŸãã @Artazor https://github.com/Microsoft/TypeScript/issues/1295#issuecomment -177287714ã«ããäžèšã®å®äžçã®äŸã¯ãããããã
ããã¯bluebirdã®awaitObject
ã§ãã ãã®æ¬åœã®æ¹æ³ã ã¿ã€ãã¯çŸåšåœ¹ã«ç«ããªãã
ããäžè¬çãªè§£æ±ºçã®æ¹ãè¯ãã§ãããã åçŽãªå Žåãšè€éãªå Žåã®äž¡æ¹ã§æ©èœããŸãã äžååãªãœãªã¥ãŒã·ã§ã³ã¯ã±ãŒã¹ã®ååã«æ¬ ããŠããããšãããããå°æ¥ãããäžè¬çãªãœãªã¥ãŒã·ã§ã³ãæ¡çšããå¿ èŠãããå Žåãäºææ§ã®åé¡ãç°¡åã«åŒãèµ·ãããŸãã
ã¯ããããã«å€ãã®äœæ¥ãå¿ èŠã§ããã @ Artazorã¯ããããŸã§èã
ãã£ãšè¯ãååãå¿ èŠãããããŸãããè©ŠããŠã¿ãŸãããéåžžã¯ãããã®ããšãæ£ããç解ããŠããŸããã ããªããžã§ã¯ããžã§ããªãã¯ãã¯ã©ãã§ããïŒ
@spion ã
awaitObject<p,T[p]>(obj: {...p:Promise<T[p]>}): Promise<{...p:T[p]}>
ïŒåºå眲åã®PromiseãèŠéããŸããïŒ
-ïŒ
@ jods4 ã
{ ...p: T[p] }
ã解決çã§ããçŸå®ã®åé¡ã¯ãããããããŸãã ååãä»ããã«ã¯ïŒreact + flux / redux
@spion @Artazor
ãããæ£ç¢ºã«æå®ããã®ãéåžžã«è€éã«ãªã£ãŠããã®ã§ã¯ãªãããšå¿é
ããŠããŸãã
ãã®åé¡ã®èåŸã«ããåæ©ã¯æŒã£ãŠããŸãã ããšããšã¯ããªããžã§ã¯ããã£ãŒã«ãã瀺ãæååãåãå ¥ããAPIããµããŒãããããšã§ããã çŸåšã¯ããªããžã§ã¯ããããããŸãã¯ã¬ã³ãŒããšããŠéåžžã«åçã«äœ¿çšããAPIã«ã€ããŠäž»ã«èª¬æããŠããŸãã 1ã€ã®ç³ã§2矜ã®é³¥ã殺ãããšãã§ããã°ãç§ã¯ããã§ãã¹ãŠã ãšããããšã«æ³šæããŠãã ããã
æååã®åé¡ãåŠçããAPIã«æ»ããšãç§ã®æèŠã§ã¯T[p]
ã¯å®å
šãªè§£æ±ºçã§ã¯ãããŸããïŒçç±ã¯åã«è¿°ã¹ãŸããïŒã
_æ£ããã®ããã«_ awaitObject
ã¯ãPromise以å€ã®ããããã£ãåãå
¥ããå¿
èŠããããŸããå°ãªããšããBluebird props
ã¯åãå
¥ããŸãã ã ããä»ç§ãã¡ã¯æã£ãŠããŸãïŒ
awaitObject<p,T[p]>(obj: { ...p: T[p] | Promise<T[p]> }): Promise<T>
ãã®è¡šèšãæ©èœããããšãæåŸ
ããŠãããããæ»ãå€ã®åãPromise<T>
ã«å€æŽããŸããã
ä»ã®ãªãŒããŒããŒãããããŸããããšãã°ããã®ãããªãªããžã§ã¯ãã«å¯ŸããŠPromiseã䜿çšãããã®ã§ãïŒãã®çœ²åã¯ããã«æ¥œããã§ãïŒã ã€ãŸãã { ...p }
è¡šèšã¯ãä»ã®ã©ã®ã¿ã€ããããäžèŽãæªããšèŠãªãå¿
èŠããããŸãã
ããããã¹ãŠãæå®ããã®ã¯å€§å€ãªäœæ¥ã«ãªããŸãã ãããæšãé²ãããã®ãªãã次ã®ã¹ãããã ãšæããŸãã
@spion @ jods4
ãã®æ©èœã¯ãžã§ããªãã¯ã¹ã«é¢ãããã®ã§ã¯ãªããããé«çš®é¡ã®ããªã¢ãŒãã£ãã¯åã«é¢ãããã®ã§ããããŸããã ããã¯ãïŒä»¥äžã§èª¬æããããã€ãã®ãé«åºŠãªãæ¡åŒµæ©èœãåããïŒå
å«åãä»ããŠããããã£ã®åãåç
§ããããã®åãªãæ§æã§ãããæŠå¿µçã«ã¯typeof
ããããã»ã©é ããããŸããã äŸïŒ
type MyType = { abcd: number };
let y: MyType["abcd"]; // Technically this could also be written as MyType.abcd
ä»æ¯èŒããŠãã ããïŒ
type MyType = { abcd: number };
let x: MyType;
let y: typeof x.abcd;
typeof
ãšã®äž»ãªéãã¯2ã€ãããŸãã typeof
ãšã¯ç°ãªããããã¯ã€ã³ã¹ã¿ã³ã¹ã§ã¯ãªãåïŒå°ãªããšãéããªããã£ãåãããã§ã¯çç¥ãããããšãå€ãäºå®ïŒã«é©çšãããŸãã ããã«ïŒããã¯éèŠãªããšã§ãïŒããªãã©ã«æååå®æ°ïŒã³ã³ãã€ã«æã«èªèãããŠããå¿
èŠããããŸãïŒãããããã£ãã¹èšè¿°åããã³ãžã§ããªãã¯ãšããŠäœ¿çšããããšããµããŒãããããã«æ¡åŒµãããŸããã
const propName = "abcd";
let y: MyType[propName];
// Or with a generic parameter:
let y: T[propName];
ãã ããæè¡çã«ã¯ã typeof
æ¡åŒµããŠãæååãªãã©ã«ããµããŒãããããšãã§ããŸãïŒããã«ã¯ã x
ããžã§ããªãã¯åã§ããå Žåãå«ãŸããŸãïŒã
let x: MyType;
const propName = "abcd";
let y: typeof x[propName];
ãŸãããã®æ¡åŒµæ©èœã䜿çšããŠãããã§ããã€ãã®ã¿ãŒã²ããã±ãŒã¹ã解決ããããšãã§ããŸãã
function get<T>(propName: string, obj: T): typeof obj[propName]
ãã ãã typeof
ã¯ãç¡æéã®ãã¹ãã¬ãã«ããµããŒãããããããã匷åã§ãã
let y: typeof x.prop.childProp.deeperChildProp
ãããŠãããã¯1ã€ã®ã¬ãã«ã ãã«ãªããŸãã ã€ãŸããïŒç§ãç¥ãéãïŒãµããŒãããäºå®ã¯ãããŸããïŒ
let y: MyType["prop"]["childProp"]["deeperChildProp"];
// Or alternatively
let y: MyType["prop.childProp.deeperChildProp"];
ãã®ææ¡ã®ç¯å²ïŒãããŸããã®ã¬ãã«ã§ã®ææ¡ãšããèšãã°ïŒã¯çããããšæããŸãã ããã¯ç¹å®ã®åé¡ã解決ããã®ã«åœ¹ç«ã€ãããããŸããïŒä»£æ¿ã®è§£æ±ºçããããããããŸãããïŒãããã¯å€ãã®äººã ããããä¿é²ããããšã«éåžžã«ç±å¿ã«ãããããã§ãã ãã ããèšèªããã®è²Žéãªæ§æãæ¶è²»ããŠããŸãã ããåºç¯ãªèšç»ãšèšèšæåã®ã¢ãããŒãããªããã°ããã®æ¥ä»ã®æç¹ã§æ確ãªä»æ§ããæã£ãŠããªããã®ãæ¥ãã§å°å ¥ããããšã¯è³¢æã§ã¯ãªãããã§ãã
_ç·šéïŒã³ãŒãäŸã®ããã€ãã®æãããªééããä¿®æ£ããŸãã_
typeof
代æ¿æ¡ã«ã€ããŠå°ã調ã¹ãŸããã
typeof x["abcd"]
ãštypeof x[42]
å°æ¥ã®èšèªãµããŒããæ¿èªãããçŸåšéçºäžã®ïŒ6606ã«åé¡ãããŸãïŒå®è£
ãæ©èœããŠããŸãïŒã
ããã¯ååã®éã®ãã§ãã ããããé 眮ãããšãæ®ãã¯ããã€ãã®æ®µéã§å®è¡ã§ããŸãã
ïŒ1ïŒååŒã®ããããã£æå®åãšããŠãæååãªãã©ã«å®æ°ïŒãŸãã¯æ°å€å®æ°-ã¿ãã«ã«åœ¹ç«ã€å¯èœæ§ããããŸããïŒïŒã®ãµããŒããè¿œå ããŸããäŸïŒ
let x: MyType;
const propName = "abcd";
let y: typeof x[propName];
ïŒ2ïŒãããã®æå®åããžã§ããªãã¯åã«é©çšã§ããããã«ãã
let x: T; // Where T should extend 'object'
const propName = "abcd";
let y: typeof x[propName];
ïŒ3ïŒãããã®æå®åãæž¡ãããããšãèš±å¯ããå®éã«ã¯é¢æ°ã®åŒæ°ãä»ããŠåç
§ããã€ã³ã¹ã¿ã³ã¹åãããŸãïŒ typeof list[0]
ãèšç»ãããŠããããã pluck
ãããªããè€éãªã±ãŒã¹ãã«ããŒã§ãããšæããŸãïŒ
function get<T extends object>(obj: T, propertyName: string): typeof obj[propertyName];
function pluck<T extends object>(list: Array<T>, propertyName: string): Array<typeof list[0][propertyName]>;
ïŒããã®object
ã¿ã€ãã¯ïŒ1809ã§ææ¡ããããã®ã§ãïŒ
ãã匷åã§ããïŒããšãã°ã typeof obj[propName][nestedPropName]
ãµããŒãããå ŽåããããŸãïŒããã®ä»£æ¿ã¢ãããŒããããã§èª¬æãããã¹ãŠã®ã±ãŒã¹ãã«ããŒããªãå¯èœæ§ããããŸãã ããã§ã¯åŠçã§ããªããšæãããäŸãããã°æããŠãã ããïŒãªããžã§ã¯ãã€ã³ã¹ã¿ã³ã¹ããŸã£ããæž¡ãããªãå Žåãé ã«æµ®ãã¶ã·ããªãªã®1ã€ã§ãããçŸæç¹ã§ã¯ããã®ãããªã±ãŒã¹ãæ³åããã®ã¯é£ããã§ããããã¯å¯èœã ãšæããŸãããããã¯å¿
èŠã§ãããïŒã
_ç·šéïŒã³ãŒãã®ããã€ãã®ééããä¿®æ£ããŸãã_
@malibuzios
ããã€ãã®èãïŒ
nameof
ãŸãã¯Expression
ãå¿
èŠã§ãã.d.ts
å®çŸ©ã§æ©èœããŸãããéåžžãéçã«æšæž¬ããããTSé¢æ°/å®è£
ã§æ€èšŒãããããããšã¯ã§ããŸãããèããã°èããã»ã©ã Expression<T, U>
ã¯ãã®ãããªçš®é¡ã®APIã®ãœãªã¥ãŒã·ã§ã³ã®ããã«èŠããŸãã ã³ãŒã«ãµã€ãã®åé¡ãçµæã®å
¥åãä¿®æ£ããå®è£
ã§æšæž¬å¯èœ+æ€èšŒå¯èœã«ããããšãã§ããŸãã
@ jods4
äžèšã®ã³ã¡ã³ãã®æ¹æ³ã§ã pluck
ã¯åŒã§å®è£
ã§ãããšãã£ããããŸããã 以åã¯CïŒã«ç²ŸéããŠããŸããããå®éã«å®éšããããšã¯ãªãã£ãã®ã§ãçŸæç¹ã§ã¯CïŒã«ã€ããŠããŸãããç解ããŠããªãããšãèªããŸãã
ãšã«ãããTypeScriptã_typeåŒæ°æšè«_ããµããŒãããŠããããšãè¿°ã¹ããã£ãã®ã§ã pluck
ã䜿çšãã代ããã«ã map
ã䜿çšããŠåãçµæãåŸãããšãã§ãããžã§ããªãã¯ãã©ã¡ãŒã¿ãŒãæå®ããå¿
èŠãããããŸããïŒããã¯æšæž¬ãããŸãïŒãããŠãŸãå®å
šãªåã®ãã§ãã¯ãšå®äºãäžããã§ãããïŒ
let x = [{name: "John", age: 34}, {name: "Mary", age: 53}];
let result = x.map(obj => obj.name);
// 'result' is ["John", "Mary"] and its type inferred as 'string[]'
map
ïŒãã¢ã³ã¹ãã¬ãŒã·ã§ã³çšã«éåžžã«ç°¡ç¥åãããŠããŸãïŒã次ã®ããã«å®£èšãããŠããå Žå
map<U>(mapFunc: (value: T) => U): U[];
ãã®åãæšè«ãã¿ãŒã³ããããªãã¯ããšããŠäœ¿çšããŠãä»»æã®ã©ã ãïŒåŒã³åºãå¿ èŠãããªãïŒã®çµæãé¢æ°ã«æž¡ãããã®æ»ãå€ã®åãé¢æ°ã«èšå®ã§ããŸãã
function thisIsATrick<T, U>(obj: T, onlyPassedToInferTheReturnType: () => U): U {
return;
}
let x = {name: "John", age: 34};
let result = thisIsATrick(x, () => x.age) // Result inferred as 'number'
_ç·šéïŒç©èªäœã ãã§ãªããããã§ã©ã ãã§æž¡ãã®ã¯ã°ãããŠããããã«èŠãããããããŸããïŒ ãã ãããã¹ãããããªããžã§ã¯ãïŒ x.prop.Childprop
ïŒã®ãããªããè€éãªã±ãŒã¹ã§ã¯ããšã©ãŒã«ãªãå¯èœæ§ã®ããæªå®çŸ©ãŸãã¯nullã®åç
§ãååšããå¯èœæ§ããããŸãã å¿
ãããåŒã³åºããããšã¯éããªãã©ã ãã«å«ããããšã§ããããåé¿ã§ããŸãã_
ããã§èª¬æããããã€ãã®ãŠãŒã¹ã±ãŒã¹ã«ã€ããŠã¯ãããŸã詳ãããªãããšãèªããŸãã å人çã«ã¯ãããããã£åãæååãšããŠåãåãé¢æ°ãåŒã³åºãå¿ èŠæ§ãæããããšã¯ãããŸããã ã©ã ãïŒããªãã説æããå©ç¹ãåœãŠã¯ãŸãïŒãååŒæ°ã€ã³ã¿ãŒãã§ãŒã¹ãšçµã¿åãããŠæž¡ãããšã¯ãéåžžãå€ãã®äžè¬çãªåé¡ã解決ããã®ã«ååã§ãã
ç§ãtypeof
代æ¿ã¢ãããŒããææ¡ããçç±ã¯ãã»ãšãã©ã®å Žåããããã»ãŒåããŠãŒã¹ã±ãŒã¹ãã«ããŒãã人ã
ãããã§èª¬æãããã®ãšåãæ©èœãæäŸããããã«æãããããã§ãã èªåã§äœ¿çšããŸããïŒ ããããªããæ¬åœã®å¿
èŠæ§ãæããããšã¯ãããŸããïŒã¢ã³ããŒã¹ã³ã¢ã®ãããªå€éšã©ã€ãã©ãªãã»ãšãã©äœ¿çšããªããšããããšãããããŸãããã»ãšãã©ã®å Žåãå¿
èŠã«å¿ããŠèªåã§ãŠãŒãã£ãªãã£é¢æ°ãéçºããŸãïŒã
@malibuzios確ãã«ã pluck
ã¯ã©ã ã+ map
çµã¿èŸŒãŸããŠããã®ã§å°ãã°ãããŠããŸãã
ãã®ã³ã¡ã³ãã§ã¯ããã¹ãŠæååãåãåã5ã€ã®ç°ãªãAPIãæäŸããŸãããããã¯ãã¹ãŠãå€æŽã®ç£èŠã«æ¥ç¶ãããŠããŸãã
@ jods4ãªã©
ïŒ6606ãå®äºãããšãã¹ããŒãž1ãå®è£ ããã ãã§ïŒå®æ°æååãªãã©ã«ãããããã£æå®åãšããŠäœ¿çšã§ããããã«ããïŒãããã§å¿ èŠãªæ©èœã®äžéšãå®çŸã§ããŸãããããã»ã©ãšã¬ã¬ã³ãã§ã¯ãããŸããïŒå¿ èŠã«ãªãå ŽåããããŸãïŒãå®æ°ãšããŠå®£èšãããã¹ããŒãã¡ã³ããè¿œå ãããããããã£åïŒã
function observeProperty<T, U>(obj: T, propName: string ): Subscriber<U> {
....
}
let x = { name: "John", age: 42 };
const propName = "age";
observeProperty<typeof x, typeof x[propName]>(x, propName);
ãã ãããããå®è£
ããããã®åŽåã¯ãã¹ããŒãž2ããã³3ãå®è£
ããããã倧å¹
ã«å°ãªãå¯èœæ§ããããŸãïŒããããŸãããã1ã¯ãã§ã«ïŒ6606ã§ã«ããŒãããŠããå¯èœæ§ããããŸãïŒã ã¹ããŒãž2ãå®è£
ãããŠããå Žåãããã¯x
ããžã§ããªãã¯åã§ããå Žåãã«ããŒããŸãïŒãã ãããããæ¬åœã«å¿
èŠãã©ããã¯ããããŸããïŒã
ç·šéïŒå€éšå®æ°ã䜿çšããŠããããã£åã2åæžã蟌ãã ã ãã§ãªããå ¥åãæžããã ãã§ãªããååãåžžã«äžèŽããããã«ããããã§ãããããã¯ãååã®å€æŽããããã¹ãŠæ€çŽ¢ããªã©ã®ããŒã«ã§ã¯äœ¿çšã§ããŸãããåç §ããããã¯æ·±å»ãªæ¬ ç¹ã§ããããšãããããŸããã
@ jods4æååã䜿çšããªãããè¯ã解決çããŸã æ¢ããŠããŸãã nameof
ãšãã®ããªã¢ã³ãã§äœãã§ããããèããŠã¿ãŸãã
ããã«å¥ã®ã¢ã€ãã¢ããããŸãã
æååãªãã©ã«ã¯ãã§ã«åãšããŠãµããŒããããŠãããããããšãã°ã次ã®ããã«æžãããšãã§ããŸãã
let x: "HELLO";
é¢æ°ã«æž¡ããããªãã©ã«æååããžã§ããªãã¯ç¹æ®åã®åœ¢åŒãšããŠè¡šç€ºã§ããŸã
ïŒ_EditïŒãããã®äŸã¯ã s
ãé¢æ°æ¬äœã§äžå€ã«ãªãããã«ä¿®æ£ãããŸãããããã®æç¹ã§ã¯const
ã¯ãã©ã¡ãŒã¿ãŒäœçœ®ã§ãµããŒããããŠããŸããïŒ readonly
ã«ã€ããŠã¯ããããŸããïŒãããïŒ._ïŒïŒ
function func(const s: string)
s
é¢é£ä»ããããstring
ãã©ã¡ãŒã¿ã¿ã€ãã¯ãããã§ã¯æé»ã®ãžã§ããªãã¯ãšèŠãªãããšãã§ããŸãïŒæååãªãã©ã«ã«ç¹åã§ããããïŒã ããããããããããã«ãããæ確ã«èšè¿°ããŸãïŒãã ããæ¬åœã«å¿
èŠãã©ããã¯ããããŸããïŒã
function func<S extends string>(const s: S)
func("TEST");
å éšçã«æ¬¡ã®ããšã«ç¹åã§ããŸãã
function func(s: "TEST")
ãããŠä»ãããã¯ããããã£åããæž¡ããããã®ä»£æ¿æ¹æ³ãšããŠäœ¿çšã§ããŸããããã¯ãããã§ã»ãã³ãã£ã¯ã¹ãããé©åã«æããŠãããšæããŸãã
function observeProperty<T, S extends string>(obj: T, const propName: S): Subscriber<T[S]>
x = { name: "John", age: 33};
observeProperty(x, nameof(x.age))
T[S]
ã T
ãšS
äž¡æ¹ãæ±çšãã©ã¡ãŒã¿ãŒã§ãã ã©ã³ã¿ã€ã èŠçŽ ãšã¿ã€ãã¹ã³ãŒãèŠçŽ ãæ··åšãããããããã¿ã€ãäœçœ®ã§2ã€ã®ã¿ã€ããçµã¿åãããæ¹ãèªç¶ãªããã§ãïŒäŸïŒ T[someString]
ïŒã
_ç·šéïŒäžå€ã®æååãã©ã¡ãŒã¿ã¿ã€ããæã€ããã«äŸãæžãçŽããŸããã_
ææ°ããŒãžã§ã³ã§ã¯ãªãTS 1.8.7
ã䜿çšããŠããã®ã§ã
const x = "Hello";
x
åã¯ããªãã©ã«å"Hello"
ïŒã€ãŸãã x: "Hello"
ïŒãšããŠãã§ã«æšæž¬ãããŠãããããã¯éåžžã«çã«ããªã£ãŠããŸãïŒïŒ6554ãåç
§ïŒã
ãããã£ãŠãåœç¶ã®ããšãªããããã©ã¡ãŒã¿ãŒãconst
ãšããŠå®çŸ©ããæ¹æ³ããã£ãå ŽåïŒãŸãã¯readonly
ãæ©èœããã§ããããïŒïŒïŒ
function func<S extends string>(const s: S): S
ããããç§ã¯ãããæãç«ã€ãšä¿¡ããŠããŸãïŒ
let result = func("abcd"); // type of 'result' inferred as the literal type "abcd"
ããã®ããã€ãã¯ããªãæ°ãããæè¿ã®èšèªæ©èœã«äŸåããŠããã®ã§ãç§ã¯ãããã§ããã ãæ確ã«èŠçŽããããšããŸãïŒ
ïŒ1ïŒ const
ïŒãããŠããããreadonly
ãïŒïŒæååå€æ°ãã³ã³ãã€ã«æã«æ¢ç¥ã®å€ãåãåããšãå€æ°ã¯èªåçã«åãå€ãæã€ãªãã©ã«åãåãåããŸãïŒããã¯1.8.x
ã§ã¯çºçããªãæè¿ã®åäœã ãšæããŸãïŒã
const x = "ABCD";
x
ã¿ã€ãã¯ã string
ã§ã¯ãªã"ABCD"
ã§ãããšæšæž¬ãããŸãïŒããšãã°ããããx: "ABCD"
ãŸãã
ïŒ2ïŒ readonly
é¢æ°ãã©ã¡ãŒã¿ãŒãèš±å¯ãããŠããå Žåããžã§ããªãã¯åã®readonly
ãã©ã¡ãŒã¿ãŒã¯ããã©ã¡ãŒã¿ãŒãäžå€ã§ãããããåŒæ°ãšããŠåãåã£ããšãã«ãã®åãæååãªãã©ã«ã«èªç¶ã«ç¹æ®åããŸãã
function func<S extends string>(readonly str: S);
func("ABCD");
ããã§ã S
ã¯ã string
ã§ã¯ãªããã¿ã€ã"ABCD"
ã«è§£æ±ºãããŠããŸãã
ãã ãã str
ãã©ã¡ãŒã¿ãŒãäžå€ã§ãªãå Žåãã³ã³ãã€ã©ãŒã¯ãããé¢æ°ã®æ¬äœã§åå²ãåœãŠãããªãããšãä¿èšŒã§ããŸããããããã£ãŠãæšæž¬ãããåã¯string
ãŸãã
function func<S extends string>(str: S) {
str = "DCBA"; // This may happen
}
func("ABCD");
ïŒ3ïŒãããå©çšããŠãå
ã®ææ¡ãå€æŽããŠãããããã£æå®åãã¿ã€ããžã®åç
§ã«ãªãããã«ããããšãã§ããŸããããã¯ã string
å°é¢æ°ã«ãªãããã«å¶çŽããå¿
èŠããããŸãïŒå Žåã«ãã£ãŠã¯ãã©ã³ã¿ã€ã ãšã³ãã£ãã£ã§ã¯ãªããã·ã³ã°ã«ãã³ãªãã©ã«ã¿ã€ãã®ã¿ã«å¶éããã®ãé©åãªå ŽåããããŸãããçŸåšããããè¡ãæ¹æ³ã¯å®éã«ã¯ãããŸããã
function get<T extends object, S extends string>(obj: T, readonly propName: S): T[S]
TypeScriptã¯ååŒæ°ã®æšè«ããµããŒãããŠããããããããåŒã³åºãã«ã¯ãååŒæ°ãæ瀺çã«æå®ããå¿ èŠã¯ãããŸããã
let x = { name: "John", age: 42 };
get(x, "age"); // result type is inferred to be 'number'
// or for stronger type safety:
get(x, nameof(x.age)); // result type is inferred to be 'number'
_ç·šéïŒããã€ãã®ã¹ãã«ãšã³ãŒãã®ééããä¿®æ£ããŸããã_
_泚ïŒãã®å€æŽãããã¢ãããŒãã®äžè¬åããã³æ¡åŒµããŒãžã§ã³ãïŒ7730ã§è¿œè·¡ãããããã«ãªããŸããã_
ããã¯ã@ Raynosãšã®è©±ãåãã§åºãŠãããã¿ã€ãããããã£ã¿ã€ãïŒãŸãã¯æè¿åŒãã§ãããã€ã³ããã¯ã¹ä»ããžã§ããªãã¯ãïŒã®å¥ã®äœ¿çšæ³ã§ãã
é åã«ã€ããŠã¯ããã§ã«æ¬¡ã®äžè¬çãªãã§ãã«ãŒãäœæã§ããŸãã
function tArray<T>(f:(t:any) => t is T) {
return function (a:any): a is Array<T> {
if (!Array.isArray(a)) return false;
for (var k = 0; k < a.length; ++k)
if (!f(a[k])) return false;
return true;
}
}
function tNumber(n:any): n is number {
return typeof n === 'number'
}
var isArrayOfNumber = tArray(tNumber)
function test(x: {}) {
if (isArrayOfNumber(x)) {
return x[x.length - 1].toFixed(2); // this type checks
}
}
ãžã§ããªãã¯ã¹ã®ã€ã³ããã¯ã¹ãäœæãããšããªããžã§ã¯ãã®äžè¬çãªãã§ãã«ãŒãäœæããããšãã§ããŸãã
function tObject<p, T[p]>(checker: {...p: (t:any) => t is T[p]}) {
return function(obj: any): obj is {...p: T[p] } {
for (var key in checker) if (!checker[key](obj[key])) return false;
return true;
}
}
ããã¯ãæååãæ°å€ãããŒã«å€ãnullãããã³æªå®çŸ©ã®ããªããã£ããã§ãã«ãŒãšäžç·ã«äœ¿çšãããšã次ã®ããã«èšè¿°ã§ããŸãã
var isTodoList = tObject({
items: tArray(tObject({text: tString, completed: tBoolean})),
showCompleted: tBoolean
})
åæã«ãé©åãªã©ã³ã¿ã€ã ãã§ãã«ãŒãšã³ã³ãã€ã«æã®åã¬ãŒãã䜿çšããŠçµæãååŸããŸã:)
誰ããããã«ã€ããŠãŸã äœãä»äºãããããšããããŸããããããšã誰ãã®ã¬ãŒããŒã«ä¹ã£ãŠããŸããïŒ ããã¯ã lodash
ãramda
ãªã©ãå€ãã®ããŒã¿ããŒã¹ã€ã³ã¿ãŒãã§ã€ã¹ãªã©ãã¿ã€ãã³ã°ã䜿çšã§ããæšæºã©ã€ãã©ãªã®æ°ã倧å¹
ã«æ¹åãããã®ã§ãã
@malibuziosç§ã¯ããªãã@Artazorã®ææ¡ã«è¿ã¥ããŠãããšä¿¡ããŠ:)
ããªãã®æžå¿µã«å¯ŸåŠããã«ã¯ïŒ
function func<S extends string>(readonly str: S): T[str] {
...
}
ããã¯
function func<S extends string, T[S]>(str: S):T[S] { }
ãã®ããã«ã次ã®ã³ãã³ãã§åŒã³åºããããšãååã¯æãå ·äœçãªåïŒæååå®æ°åïŒã«ããã¯ãããŸãã
func("test")
ã¿ã€ãS
ã¯"test"
ïŒ string
ã¯ãããŸããïŒã ãã®ããã str
å¥ã®å€ãåå²ãåœãŠããããšã¯ã§ããŸããã ããªãããããè©Šããå ŽåãäŸãã°
str = "other"
ã³ã³ãã€ã©ã¯ãšã©ãŒãçæããå¯èœæ§ããããŸãïŒåæ£ã®å¥å šæ§ã®åé¡ããªãéã;ïŒïŒ
1ã€ã®ããããã£ã®åãååŸããã ãã§ãªããä»»æã®ã¹ãŒããŒåã®åãååŸãããªãã·ã§ã³ãå¿ èŠã§ãã
ãããã£ãŠãç§ã®ææ¡ã¯ã次ã®æ§æãè¿œå ããããšã§ãã T[prop]
ã ãã§ãªããæ§æT[...props]
ãè¿œå ããããšæããŸãã ããã§ã props
ã¯T
ã®ã¡ã³ããŒã®é
åã§ããå¿
èŠããããŸãã ãããŠãçµæã®åã¯ãã®ã¹ãŒããŒã¿ã€ãã§ããT
ã®ã¡ã³ããŒãšT
ã§å®çŸ©ãããprops
ã
node.jsã§äººæ°ã®ããORMã§ããSequelizeã§éåžžã«åœ¹ç«ã€ãšæããŸãã ã»ãã¥ãªãã£äžã®çç±ãšããã©ãŒãã³ã¹äžã®çç±ããã䜿çšããå¿ èŠã®ããããŒãã«ã®å±æ§ãã¯ãšãªããããšããå§ãããŸãã ããã¯ãã°ãã°ã¿ã€ãã®ã¹ãŒããŒã¿ã€ããæå³ããŸãã
interface IUser {
id: string;
name: string;
email: string;
createdAt: string;
updatedAt: string;
password: string;
// ...
}
interface Options<T> {
attributes: (memberof T)[];
}
interface Model<IInstance> {
findOne(options: Options<IInstance>): IInstance[...options.attributes];
}
declare namespace DbContext {
define<T>(): Model<T>;
}
const Users = DbContext.define<IUser>({
id: { type: DbContext.STRING(50), allowNull: false },
// ...
});
const user = Users.findOne({
attributes: ['id', 'email', 'name'],
where: {
id: 1,
}
});
user.id
user.email
user.name
user.password // error
user.createdAt // error
user.updatedAt // error
ïŒç§ã®äŸã§ã¯ãæåŸ
ã©ããã®æŒç®åmemberof
ãšã typeof options.attributes
ãšåãåŒoptions.attributes
ãå«ãŸããŠããŸããã typeof
æŒç®åã¯ãåãäºæããäœçœ®ã«ããããããã®å Žåã¯åé·ã§ããïŒ
誰ã䞻匵ããªããªããç§ã¯ããã«åãçµã¿å§ããŸããã
é¢æ°å ã®åã®å®å šæ§ã«ã€ããŠã©ãæããŸããïŒã€ãŸããreturnã¹ããŒãã¡ã³ããæ»ãå€ã®åã«å²ãåœãŠå¯èœãªãã®ãè¿ãããã«ããŸããïŒ
interface A {
a: string;
}
function f(p: string): A[p] {
return 'aaa'; // This is string, but can we ensure it is the intended A[p] ?
}
ãŸããããã§äœ¿çšãããŠãããããããã£ã¿ã€ãããšããååã¯å°ãééã£ãŠããããã§ãã ããã¯ãã¿ã€ãã«ããããã£ããããã»ãŒãã¹ãŠã®ã¿ã€ãã«ããããã£ãããããšã瀺ããŠããŸãã
ãããããã£åç §åãã¯ã©ãã§ããïŒ
é¢æ°å ã®åå®å šæ§ã«ã€ããŠã©ãæããŸãã
ç§ã®ãã¬ã€ã³ã¹ããŒãã³ã°ïŒ
let a: A;
function f(p: string): A[p] {
let x = a[p]; // typeof A[p], only when:
// 1. p is directly referencing function argument
// 2. function return type is Property Reference Type
p = "abc"; // not allowed to assign a new value when p is used on Property Reference Type
return x; // x is A[p], so okay
}
ãããŠãæ»ãè¡ã®éåžžã®æååãçŠæ¢ããŸãã
@malibuziosã®ã¢ã€ãã¢ã®åé¡ã¯ãæšæž¬ã§ããªãå Žåã«åããŠãã¹ãŠã®ãžã§ããªãã¯ãæå®ããå¿ èŠãããããšã§ããããã¯ããŠã€ã«ã¹ãã³ãŒãããŒã¹ã®æ±æã«
https://github.com/Microsoft/TypeScript/issues/1295#issuecomment -239653337ã«é¢ããTSããŒã ããã®ã³ã¡ã³ãã¯ãã
@RyanCavanaugh @mhegazyãªã©ïŒ
ååã«é¢ããŠã¯ããã®æ©èœïŒå°ãªããšã@Artazorãææ¡ãã圢åŒïŒããã€ã³ããã¯ã¹ä»ããžã§ããªãã¯ããšåŒã³å§ããŸããã
å¥ã®èŠ³ç¹ããã®è§£æ±ºçã¯ããã®åé¡ã«å¯Ÿãããã®ã§ããå¯èœæ§ããããŸãã ãã§ã«æã£ãŠããŠãããã©ããã¯ããããŸããããé·ãã¹ã¬ããã§ãã æååã®äžè¬çãªææ¡ãäœæããŠãã€ã³ããã¯ã¹çœ²åãæ¡åŒµã§ããŸãã æååãªãã©ã«ã¯ã€ã³ãã¯ãµãŒã¿ã€ãã«äœ¿çšã§ãããããããããåçã«ããããšãã§ããŸãïŒçŸæç¹ã§ã¯ããã§ã¯ãªãããšãããã£ãŠããŸãïŒã
interface A1 {
a: number;
b: boolean;
}
interface A2 {
[index: "a"]: number;
[index: "b"]: boolean;
}
ã ãããç§ãã¡ã¯ãã æžãããšãã§ããŸã
declare function pluck<P, T extends { [indexer: P]: R; }, R>(obj: T, p: P): R;
èæ ®ããå¿ èŠãããããšãããã€ããããŸãã
P
ãæååãªãã©ã«ã®ã¿ã«ãªãåŸãããšã瀺ãæ¹æ³ã¯ïŒP extends string
ã¯ããŸãã€ããªããã£ãã¯ã§ã¯ãããŸããP super string
å¶çŽã®èš±å¯ã«ã€ããŠä»ã®è°è«ãè¡ãããŠããŸãïŒïŒ7265ãïŒ6613ãhttpsïŒ//github.com/Microsoft/TypeScript/issues/6613#issuecomment-175314703ïŒT
ã«string
ãŸãã¯number
ã®ã€ã³ãã¯ãµãŒãããå Žåãã€ã³ãã¯ãµãŒã¿ã€ãã«åãå
¥ãããããã®ãªãäœã§ã䜿çšã§ããŸãã ãã®å Žåã P
ã¯string
ãŸãã¯number
ãŸãã"something"
ãæž¡ããšãã¿ã€ãã¯string
P
ã䜿çšããå¿
èŠããããšæšæž¬ã§ããŸãã{ [i: string]: number /* | undefined */ }
undefined
ãæ¬åœã«å
¥ããããªãå Žåãã©ã®ããã«åŒ·å¶ããã®ã§ããïŒP
ã T
ã R
éã®ãã¹ãŠã®é¢ä¿ã®èªååæšè«ã¯ããããæ©èœãããããã®éµã§ã@weswigham @mhegazy ããããŠç§ã¯æè¿ããã«ã€ããŠè©±ãåã£ãŠããŸãã çºçããéçºã«ã€ããŠãç¥ããããŸããããã¯ã¢ã€ãã¢ã®ãããã¿ã€ããäœæããã ãã§ããããšã«æ³šæããŠãã ããã
çŸåšã®ã¢ã€ãã¢ïŒ
Foo
ããããããã£åã®åéåãååŸããããã®keysof Foo
æŒç®åãFoo[K]
ã¿ã€ããããã¯ãäžéšã®ã¿ã€ãã®K
ããæååãªãã©ã«ã¿ã€ããŸãã¯æååãªãã©ã«ã¿ã€ãã®åéåã§ããããšãæå®ããŸãããããã®åºæ¬ãããã¯ãããé©åãªã¿ã€ããšããŠæååãªãã©ã«ãæšæž¬ããå¿ èŠãããå Žåã¯ã次ã®ããã«èšè¿°ã§ããŸãã
function foo<T, K extends keysof T>(obj: T, key: K): T[K] {
// ...
}
ããã§ã K
ã¯keysof T
ãµãã¿ã€ãã«ãªããŸããããã¯ãæååãªãã©ã«åãŸãã¯æååãªãã©ã«åã®åéåã§ããããšãæå³ããŸãã key
ãã©ã¡ãŒã¿ã«æž¡ããã®ã¯ãã¹ãŠããã®ãªãã©ã«/ãªãã©ã«ââã®åéåã«ãã£ãŠã³ã³ããã¹ãã§åæå®ãããã·ã³ã°ã«ãã³æååãªãã©ã«åãšããŠæšæž¬ãããå¿
èŠããããŸãã
äŸãã°
interface HelloWorld { hello: any; world: any; }
function foo<K extends keysof HelloWorld>(key: K): K {
return key;
}
// 'x' has type '"hello"'
let x = foo("hello");
æ倧ã®åé¡ã¯ã keysof
ããã°ãã°ãã®æäœããé
ããããå¿
èŠããããšããããšã§ãã åãè©äŸ¡ããæ¹æ³ã«ç±å¿ãããŸããããã¯ãç§ãæçš¿ããæåã®äŸã®ããã«åãã©ã¡ãŒã¿ãŒã®åé¡ã§ãïŒã€ãŸããæ¬åœã«è§£æ±ºãããã®ã¯ãå®éã«ã¯é£ããéšåã§ãïŒsmile :)ã
ãããããªãã«ãã¹ãŠã®ã¢ããããŒããäžããããšãé¡ã£ãŠããŸãã
@DanielRosenwasseræŽæ°ããŠããã ãããããšãããããŸãã @weswighamãkeysof
ãªãã¬ãŒã¿ãŒã«é¢ããPRãæåºããã®ãèŠãã°ãããªã®ã§ããã®åé¡ãçããã«æž¡ãæ¹ãè¯ããããããŸããã
ãªãããªãã¯æåã«ææ¡ãããæ§æããé¢ããããšã決ããã®ã ãããïŒ
function get(prop: string): T[prop];
keysof
ã玹ä»ããŸããïŒ
T[prop]
ã¯ããã»ã©äžè¬çã§ã¯ãªããå€ãã®ã€ã³ã¿ãŒã¬ãŒã¹æ©æ¢°ãå¿
èŠãšããŸãã ããã§äžã€ã®å€§ããªåé¡ã¯ãããªããã®æåéãã®å
容é¢é£ãããæ¹æ³ã§ãprop
ã®ããããã£åã«T
ã ç§ã¯ããªããäœãããã®ãå®å
šã«ã¯ããããŸããã æé»ã®åãã©ã¡ãŒã¿ãŒãè¿œå ããŸããïŒ ã³ã³ããã¹ãã¿ã€ãã³ã°ã®åäœãå€æŽããå¿
èŠããããŸããïŒ çœ²åã«äœãç¹å¥ãªãã®ãè¿œå ããå¿
èŠããããŸããïŒ
çãã¯ããããããããã¹ãŠã«ã€ãšã¹ã§ãã ç§ã®è žã¯ã2ã€ã®ããåçŽã§å¥ã ã®æŠå¿µã䜿çšããããããæ§ç¯ããæ¹ããããšç§ã«èšã£ãã®ã§ãç§ã¯ããããç§ãã¡ãè¿œãåºããŸããã æ¬ ç¹ã¯ãç¹å®ã®å Žåã«ãã€ã©ãŒãã¬ãŒããå°ãå¢ããããšã§ãã
ãããã®çš®é¡ã®ãã¿ãŒã³ã䜿çšããæ°ããã©ã€ãã©ãªãããããã®å®åæã«ãã£ãŠTypeScriptã§ã®èšè¿°ãå°é£ã«ãªã£ãŠããå Žåã¯ããããæ€èšããå¿ èŠããããŸãã ããããå šäœãšããŠããã®æ©èœã¯äž»ã«å³æžé€šã®æ¶è²»è ã«ãµãŒãã¹ãæäŸããããšãç®çãšããŠããŸãããšã«ããã䜿çšãµã€ãã¯ããã§ã¡ãªãããåŸãå Žæã ããã§ãã
@DanielRosenwasserãããã®ç©ŽããããããŠéããã @SaschaNazã®ã¢ã€ãã¢ã®å®è£
ã«ãŸã åé¡ã¯ãããŸãããïŒ ãã®å Žåã keysof
ã¯åé·ã ãšæããŸãã T[p]
ã p
ãT
ã®æåéãã®å°éå
·ã®1ã€ã§ãªããã°ãªããªãããšããã§ã«ç€ºããŠããŸãã
ç§ã®å€§ãŸããªå®è£
ã®èãã¯ã PropertyReferencedType
ãšåŒã°ããæ°ããã¿ã€ããå°å
¥ããããš
export interface PropertyReferencedType extends Type {
property: Symbol;
targetType: ObjectType;
}
PropertyReferencedType
æ»ãå€ã®åã§å®£èšãããé¢æ°ãå
¥åãããã PropertyReferencedType
ãåç
§ããé¢æ°ãå
¥åããå ŽåïŒ ElementAccessExpression
åã¯ããåç
§ããããããã£ã§æ¡åŒµãããŸããã¢ã¯ã»ã¹ãããããããã£ã®ã·ã³ãã«ã
export interface Type {
flags: TypeFlags; // Flags
/* <strong i="20">@internal</strong> */ id: number; // Unique ID
//...
referencedProperty: Symbol; // referenced property
}
ãããã£ãŠãåç
§ãããããããã£ã·ã³ãã«ãæã€ã¿ã€ãã¯ã PropertyReferencedType
å²ãåœãŠãããšãã§ããŸãã ãã§ãã¯äžã referencedProperty
p
ã¯T[p]
p
ã«å¯Ÿå¿ããŠããå¿
èŠããããŸãã ãŸããèŠçŽ ã¢ã¯ã»ã¹åŒã®èŠªã¿ã€ãã¯ã T
å²ãåœãŠå¯èœã§ããå¿
èŠããããŸãã ãããŠãç©äºãç°¡åã«ããããã«ã p
ãconstã§ãªããã°ãªããŸããã
æ°ããã¿ã€ãPropertyReferencedType
ã¯ããæªè§£æ±ºã®ã¿ã€ãããšããŠé¢æ°å
ã«ã®ã¿ååšããŸãã ã³ãŒã«ãµã€ãã§ã¯ãã¿ã€ããp
解決ããå¿
èŠããããŸãã
interface A { a: string }
declare function getProp(p: string): A[p]
getProp('a'); // string
PropertyReferencedType
ã¯é¢æ°ã®å²ãåœãŠãä»ããŠã®ã¿äŒæããåŒã³åºãåŒãä»ããŠäŒæããããšã¯ã§ããŸããã PropertyReferencedType
ã¯ãæ»ãå€ã®åT[p]
ãæã€é¢æ°ã®æ¬äœã®ãã§ãã¯ãæ¯æŽããããã®äžæçãªåã«ãããªãããã§ãã
keysof
ãšT[K]
åã®æŒç®åãå°å
¥ããå Žåã次ã®ããã«äœ¿çšã§ããããšãæå³ããŸãã
interface A {
a: number;
b: string;
}
type AK = keysof A; // "a" | "b"
type AV = A[AK]; // number | string ?
type AA = A["a"]; // number ?
type AB = A["b"]; // string ?
type AC = A["c"]; // error?
type AN = A[number]; // error?
type X1 = keysof { [index: string]: number; }; // string ?
type X2 = keysof { [index: string]: number; [index: number]: string; }; // string | number ?
@DanielRosenwasserããªãã®äŸã¯ç§ã®äŸãšåãæå³ã§ã¯ãªãã§ããã
function foo<T, K extends keysof T>(obj: T, key: K): T[K] {
// ...
}
// same as ?
function foo<K, V, T extends { [k: K]: V; }>(obj: T, key: K): V {
// ...
}
ã¢ã³ããŒã¹ã³ã¢ã®_.pick
ã®çœ²åãã©ã®ããã«æžã蟌ãŸãããããããŸããïŒ
o2 = _.pick(o1, 'p1', 'p2');
pick(Object, ...props: String[]) : WHAT GOES HERE;
@rtmhttps ïŒ //github.com/Microsoft/TypeScript/issues/1295#issuecomment-234724380ã§ææ¡ããŸããã ããã«é¢é£ããŠããŠããæ°ããå·ãéãæ¹ãè¯ããããããŸãããã
å®è£ ã¯ïŒ11929ã§å©çšå¯èœã«ãªããŸããã
æãåèã«ãªãã³ã¡ã³ã
@weswigham @mhegazy ããããŠç§ã¯æè¿ããã«ã€ããŠè©±ãåã£ãŠããŸãã çºçããéçºã«ã€ããŠãç¥ããããŸããããã¯ã¢ã€ãã¢ã®ãããã¿ã€ããäœæããã ãã§ããããšã«æ³šæããŠãã ããã
çŸåšã®ã¢ã€ãã¢ïŒ
Foo
ããããããã£åã®åéåãååŸããããã®keysof Foo
æŒç®åãFoo[K]
ã¿ã€ããããã¯ãäžéšã®ã¿ã€ãã®K
ããæååãªãã©ã«ã¿ã€ããŸãã¯æååãªãã©ã«ã¿ã€ãã®åéåã§ããããšãæå®ããŸãããããã®åºæ¬ãããã¯ãããé©åãªã¿ã€ããšããŠæååãªãã©ã«ãæšæž¬ããå¿ èŠãããå Žåã¯ã次ã®ããã«èšè¿°ã§ããŸãã
ããã§ã
K
ã¯keysof T
ãµãã¿ã€ãã«ãªããŸããããã¯ãæååãªãã©ã«åãŸãã¯æååãªãã©ã«åã®åéåã§ããããšãæå³ããŸããkey
ãã©ã¡ãŒã¿ã«æž¡ããã®ã¯ãã¹ãŠããã®ãªãã©ã«/ãªãã©ã«ââã®åéåã«ãã£ãŠã³ã³ããã¹ãã§åæå®ãããã·ã³ã°ã«ãã³æååãªãã©ã«åãšããŠæšæž¬ãããå¿ èŠããããŸããäŸãã°
æ倧ã®åé¡ã¯ã
keysof
ããã°ãã°ãã®æäœããé ããããå¿ èŠããããšããããšã§ãã åãè©äŸ¡ããæ¹æ³ã«ç±å¿ãããŸããããã¯ãç§ãæçš¿ããæåã®äŸã®ããã«åãã©ã¡ãŒã¿ãŒã®åé¡ã§ãïŒã€ãŸããæ¬åœã«è§£æ±ºãããã®ã¯ãå®éã«ã¯é£ããéšåã§ãïŒsmile :)ããããããªãã«ãã¹ãŠã®ã¢ããããŒããäžããããšãé¡ã£ãŠããŸãã