typescript2.4 - Typescript keyof extra type condition -
i want pass 2 generic condition pass array type field name not accepted second condition.
this method declaration , no problem.
firstordefault<k extends keyof t>(predicate?: (item: t) => boolean, recursiveitem?: k): t;
above method declaration working want pass array type in recurviseitem field.
i'm trying method declaration doesn't work.
firstordefault<k extends keyof t & t[]>(predicate?: (item: t) => boolean, recursiveitem?: k): t
how can solve problem?
sample code
let departments : idepartment[] = [ { name: 'manager', subdepartments: [ { name: 'accountant' } ] } ] // method declaration , code worked can pass name , subdepartments field pass recursiveitem parameter want t[] type field pass subdepartments. let department = departments.firstordefault(d => d.name == 'accountant', 'subdepartments') console.log(department) interface array<t> { firstordefault<k extends keyof t>(predicate?: (item: t) => boolean, recursiveitem?: k): t; } array.prototype.firstordefault = function(this, predicate, recursiveitem) { if (!predicate) return this.length ? this[0] : null; (var = 0; < this.length; i++) { let item = this[i] if (predicate(item)) return item if (recursiveitem) { let subitems = item[recursiveitem] if (array.isarray(subitems)) { var res = subitems.firstordefault(predicate, recursiveitem) if (res) return res } } } return null; } interface idepartment { name?: string, subdepartments?: idepartment[] }
i don't think there's great answer. looking type function identifies properties of type t
values of type array<t>
(or array<t> | undefined
since optional properties that). naturally expressed mapped conditional types, not yet part of typescript. in case, make like
type valueof<t> = t[keyof t]; type restrictedkeys<t> = valueof<{ [k in keyof t]: if<matches<t[k],array<t>|undefined>, k, never> }>
and annotate recursiveitem
parameter type restrictedkeys<t>
, done. can't that.
the solution i've works give on extending array
prototype. (that's bad practice anyway, isn't it?) if okay standalone function first parameter array<t>
, can this:
function firstordefault<k extends string, t extends partial<record<k, t[]>>>(arr: array<t>, pred?: (item: t) => boolean, rec?: k): t | null { if (!pred) return this.length ? this[0] : null; (var = 0; < this.length; i++) { let item = this[i] if (pred(item)) return item if (rec) { let subitems = item[rec] if (array.isarray(subitems)) { var res = firstordefault(subitems, pred, rec) if (res) return res } } } return null; }
in above, can restrict type t
partial<record<k,t[]>>
, meaning t[k]
optional property of type array<t>
. expressing restriction on t
, type checker behaves you'd like:
firstordefault(departments, (d:idepartment)=>d.name=='accountant', 'subdepartments') // okay firstordefault(departments, (d:idepartment)=>d.name=='accountant', 'name') // error firstordefault(departments, (d:idepartment)=>d.name=='accountant', 'random') // error
as said, there's no great way take above solution , make work extending array<t>
interface, since works restricting t
. in theory, express k
in terms of t
, keyof (t & partial<record<k,t[]>>
, typescript not aggressively evaluate intersections eliminate impossible types, still accepts name
, though inferred type of name
property string & idepartment[]
shouldn't exist.
anyway, hope above solution can work you. luck!
edit: see you've solved own problem relaxing different requirement: recursiveitem
parameter no longer key name. still think should consider standalone function solution, since works intended , doesn't pollute prototype of array
. it's choice, of course. luck again!
Comments
Post a Comment