292

I'm using Chrome 70 and Chrome does add methods .flatMap, .flatten, .flat. So my code does run as expected. Unfortunately, TypeScript doesn't like it.

// data.flatMap lint error
export const transformData = (data: any[]) => data.flatMap(abc => [
   parentObj(abc),
   ...generateTasks(abc)
]);

The warning I got is TS2339: Property 'flatMap' does not exist on type 'any[]'.

I'm using Angular 6, which uses Typescript ~2.9.2, and I already include import 'core-js/es7/array'; in polyfills.ts.

My guess is that there is no typing for these methods, and I did try to npm run -dev @types/array.prototype.flatmap but still not solve.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Azriz
  • 3,122
  • 2
  • 12
  • 13

7 Answers7

554

You should add es2019 or es2019.array to your --lib setting for TypeScript to recognize array.flat() and flatMap().

Example:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "es2019"
    ]
  }
}

Previously this was available as part of esnext or esnext.array, but it's now officially part of ES2019.

Aaron Beall
  • 49,769
  • 26
  • 85
  • 103
  • 8
    Yup I reproduce this and it works. Here my `compilerOptions` in `tsconfig.app.json` `"lib": [ "es2017", "dom", "esnext.array", ]` Thank you sir – Azriz Dec 03 '18 at 03:07
  • 9
    This did not fix it for me in my IDE, VSCode. Any tips? – timelfelt Apr 25 '19 at 22:13
  • 15
    @timelf123 did you restart your IDE? – Highspeed May 20 '19 at 22:18
  • 1
    Is there a reason (and if so what's the effect) of using `"esnext"` instead of `"esnext.array"`? – maninak Jun 03 '19 at 14:12
  • 1
    @maninak `"esnext"` just includes [additional stuff](https://github.com/microsoft/TypeScript/blob/master/lib/lib.esnext.d.ts) besides the array proposals. – Aaron Beall Jun 03 '19 at 16:29
  • Replacing esnext, esnext.array or es2017 with es2019 got it to work for me. – Blair Zajac Aug 10 '19 at 23:54
  • @BlairZajac Yep, Array stuff is officially part of ES2019 now, so I updated the answer. Thanks for the tip! – Aaron Beall Aug 15 '19 at 20:58
  • 9
    Note: flatMap is now supported in node 11+ – JeffMinsungKim Oct 01 '19 at 06:17
  • @Onza It should work, the problem is likely in your build configuration not properly using your tsconfig, as the default settings don't allow flat at this time. – Aaron Beall Jan 13 '20 at 14:44
  • Nope, double checked, this is on VScode; all the other configurations seem to have an effect but this one, I have absolutely no clue, the solution of Frenton does work however; either way, I just ended up deciding not to use the method. – Onza Jan 14 '20 at 16:40
  • 2
    I think commenting under accepted answer will be more efficient. getting an error: property flat does not exist on type string[][]; shouldn't be flat of type any[] still work with string[][]. I don't know how to structure well this statement. – Janatbek Orozaly Jan 24 '20 at 22:05
  • 5
    @maninak `es2019.array` is in most cases preferred as it explicitly specifies the features of the `es2019` spec that are supported in the project which avoids accidentally using `es2019` features not supported – CervEd Mar 19 '20 at 12:17
  • is there a way to add all the esXXXX years? – mesqueeb Apr 04 '20 at 12:17
  • Worked for me to change tsconfig.json files from "lib": ["es2018"] to "lib": ["es2019"]. – Rich Finelli Apr 19 '20 at 14:26
  • Thank you, it unexpectedly and surprisingly well worked for me right away. Intellij idea was able to catch up flatMap and flat RIGHT after I added libs (I already had target:es5 configured). Usually, the process is harder.... – Pasha Apr 28 '21 at 09:43
  • This works technically but the typings are terrible. `T` will be of type `S | Array` basically, so `flat` is not of type `Array`, but fo type `Array` where S is the nested structure. I think you need to add a generic like `interface Array { flat(): Array }` or find a way to filter out array types from T. – Eric Burel Nov 29 '21 at 10:16
  • Just to add , VSC needs restarted – dragonfly02 May 12 '22 at 06:48
38

If you're are in a lower version than es2019, you can implement a shim to provide similar functionality to .flat() and .flatMap() provided by later libraries.

To flat single level array

arr.reduce((acc, val) => acc.concat(val), []);

To flat multi level array

function flatDeep(arr, d = 1) {
   return d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), []) : arr.slice();
};

to know deeply you can also check below link

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Manoj Rana
  • 3,068
  • 1
  • 24
  • 34
  • 3
    Thanks for this snippet — it was helpful as I still couldn't use `.flat()` even with the Typescript fix in the accepted answer. – David Yeiser Oct 07 '20 at 19:39
  • This snippet helped as I still couldn't get `.flat()` to work after adding `"lib": ["ES2019"],` in tsconfig.json – ranaalisaeed Apr 24 '21 at 23:49
  • be careful with `concat()` since it's a [copying method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat#description). Use `push()` instead which is a [mutating method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) – netotz Dec 10 '22 at 00:20
20

Aaron Beall's answer is excellent. It may be worth knowing that if "lib" is not specified in the tsConfig.JSON file a default list of libraries are injected. The default libraries injected are: ► For --target ES5: DOM,ES5,ScriptHost ► For --target ES6: DOM,ES6,DOM.Iterable,ScriptHost

In other words: We must specify those libs that were previously added automatically. (see: https://www.typescriptlang.org/docs/handbook/compiler-options.html for further info)

"compilerOptions": {

   "target": "es6",

   "lib": [ "es2019", "DOM", "ES6" ,"DOM.Iterable", "ScriptHost"],}
Hector Crean
  • 322
  • 2
  • 7
7

I tried most answers and they didn't work for me. IDE: VScode

but this did

npm i -D @types/node
4

You can extend the global array interface while you wait for stability, at which point it will be added to the default library.

interface Array<T> {
    flat(): Array<T>;
    flatMap(func: (x: T) => T): Array<T>;
}
Fenton
  • 241,084
  • 71
  • 387
  • 401
3

As of angular 11 and thx to typescript 3.9 this is now the new config.

"compilerOptions": {
    "target": "es2018",
    "module": "es2020",
    "lib": ["es2020", "dom"],
}

Why es2020 instead of esnext?

In TypeScript 3.9, the behavior of the TypeScript compiler controlled by module is the same with both "esnext" and "es2020" values. This behavior can change in the future, because the "esnext" option could evolve in a backwards incompatible ways, resulting in build-time or run-time errors during a TypeScript update. As a result, code can become unstable. Using the "es2020" option mitigates this risk.

for further read

Raphaël Balet
  • 6,334
  • 6
  • 41
  • 78
1

You can also add esnext to your --lib instead of 'es2019'

"compilerOptions": {
    "target": "es2015",
    "lib": ["dom", "esnext"]
}

It worked for me.