2017-02-09 12 views
3

Базовый класс массив .map, .forEach, .filter и .reduce, но .groupBy я заметно отсутствует, мешает мне делать что-то вродеarray.groupBy в машинописном

const MyComponent = (props:any) => { 
    return (
     <div> 
      { 
       props.tags 
       .groupBy((t)=>t.category_name) 
       .map((group)=>{ 
        [...] 
       }) 
      } 

     </div> 
    ) 
} 

я в конечном итоге реализации что-то себе:

class Group<T> { 
    key:string; 
    members:T[] = []; 
    constructor(key:string) { 
     this.key = key; 
    } 
} 


function groupBy<T>(list:T[], func:(x:T)=>string): Group<T>[] { 
    let res:Group<T>[] = []; 
    let group:Group<T> = null; 
    list.forEach((o)=>{ 
     let groupName = func(o); 
     if (group === null) { 
      group = new Group<T>(groupName); 
     } 
     if (groupName != group.key) { 
      res.push(group); 
      group = new Group<T>(groupName); 
     } 
     group.members.push(o) 
    }); 
    if (group != null) { 
     res.push(group); 
    } 
    return res 
} 

Так что теперь я могу сделать

const MyComponent = (props:any) => { 
    return (
     <div> 
      { 
       groupBy(props.tags, (t)=>t.category_name) 
       .map((group)=>{ 
        return (
         <ul key={group.key}> 
          <li>{group.key}</li> 
          <ul> 
           { 
            group.members.map((tag)=>{ 
             return <li key={tag.id}>{tag.name}</li> 
            }) 
           } 
          </ul> 
         </ul> 
        ) 
       }) 
      } 

     </div> 
    ) 
} 

Работает очень хорошо, но это слишком плохо, что мне нужно обернуть список, а не просто подключить вызовы методов.

Есть ли лучшее решение?

+0

машинопись не добавляет polyfills для изменения стандартной библиотеки ES6. Если вы хотите получить их, я бы предложил посмотреть на core.js :) – toskv

ответ

4

можно добавить функцию к прототипу массива в вашем приложении (обратите внимание на некоторые не рекомендую это: Why is extending native objects a bad practice?):

Array.prototype.groupBy = function(/* params here */) { 
    let array = this; 
    let result; 
    /* do more stuff here*/ 
    return result; 
}; 

Затем создать интерфейс в машинописи, как это:

.d версия .ts:

interface Array<T> 
    { 
     groupBy<T>(func:(x:T) => string): Group<T>[] 
    } 

ИЛИ в нормальном Т.С. файле:

declare global { 
    interface Array<T> 
    { 
     groupBy<T>(func:(x:T) => string): Group<T>[] 
    } 
} 

Затем вы можете использовать:

props.tags.groupBy((t)=>t.category_name) 
    .map((group)=>{ 
        [...] 
       }) 
+0

Будет ли компилятор автоматически отображать интерфейс 'Array ' и объединить его с существующим определением? Или у меня будет два типа массива? – Eldamir

+0

Да, он поднимет его. Мы используем его в нашем приложении alot –

+0

Интересно. Спасибо – Eldamir