776

Code is:

const foo = (foo: string) => {
  const result = []
  result.push(foo)
}

I get the following TS error:

[ts] Argument of type 'string' is not assignable to parameter of type 'never'.

What am I doing wrong? Is this a bug?

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Lev
  • 13,856
  • 14
  • 52
  • 84
  • 6
    `const result: [] = []` => `const result: string[]`, *not* just `[]`, but `string[]`, if you don't know the type inside the array, you can always fallback to `any[]` – jave.web Apr 09 '22 at 15:37

20 Answers20

1011

All you have to do is define your result as a string array, like the following:

const result : string[] = [];

Without defining the array type, it by default will be never. So when you tried to add a string to it, it was a type mismatch, and so it threw the error you saw.

YakovL
  • 7,557
  • 12
  • 62
  • 102
  • 62
    That seems bizarre to me, why default to `never[]` ? is there ever a use for that except "an array that will ALWAYS be empty?" – Vincent Buscarello Feb 28 '19 at 20:56
  • 16
    I totally agree because, to be honest, I can't think of a use case that an array of `never`s will be useful. But while looking into it I came across this [answer](https://stackoverflow.com/a/49225093/6427646) which has great info. – Tha'er AlAjlouni ثائر العجلوني Mar 01 '19 at 11:42
  • 42
    Shouldn't the default type be "any"? When you declare a variable (`let x;` ) it is of type `any` by default. Not `never`. – Shachar Har-Shuv May 07 '19 at 08:53
  • 6
    Definitely would expect an array without type to be `any[]`. Was surprised it was `never[]` which makes it useless. Unintuitive. Thanks for the answer. edit: grammar – Igor Malyk Dec 24 '19 at 10:38
  • 17
    @VincentBuscarello I guess, the main point of such default is to make one to always add types to their arrays; but the error message is definitely not helpful. – YakovL Dec 27 '19 at 14:24
  • 1
    I've just ran into the similar problem with the `useState()` react hook and an array of objects named `Survey` (ie. `Survey[]`). My fix looked like this: `const [surveys, setSurveys] = useState([]);` – micmania1 Dec 31 '19 at 04:33
  • 4
    I always like to know where these changes happened in the source code for better understanding so for those curious see: https://github.com/Microsoft/TypeScript/issues/9976 and https://github.com/microsoft/TypeScript/pull/8944 – ksrb Jan 26 '20 at 20:42
  • 1
    Seems like it properly defaults to `any[]` now (typescript 3.8). https://www.typescriptlang.org/play/index.html#code/MYewdgzgLgBAZiEMC8MAUCQC4bQE4CWYA5gJQoB8MA3gFAwyiSx4CmEArgDayoDaAXXow2nHgDoADhwgALDIlK0AvkA – Aleksey L. Apr 17 '20 at 16:18
  • 1
    I would like to ignore this error in my tsLint. What is this rule? – AKJ Apr 16 '21 at 11:49
  • 1
    On one hand, the point of TS is to make things type-safe, so you make it impossible add string to an untyped array. On the other hand, TS advertises itself as progressively applicable, meaning you can use little or no TS as you'd like. So there seems to be a disconnection here. – J.Ko Aug 20 '21 at 17:48
  • I got this error trying to do `obj[prop] = []`, how do I type that? – Boris Verkhovskiy Mar 29 '22 at 08:51
  • No type inference? – Alper Oct 19 '22 at 21:55
129

Another way is:

const result: any[] = [];
neomib
  • 3,503
  • 4
  • 17
  • 27
  • 76
    Actually using `any` isn't a good option, because it basically turns off any TypeScript features. It's a workaround and can lead to various bugs. – Tomek Buszewski Jul 12 '19 at 09:05
  • 10
    Yes. But sometimes nothing else works especially when you are working with third-party libraries.. – neomib Jul 14 '19 at 07:53
  • 17
    wouldnt `const result: any[] = []` be more accurate? its an array of any not and array treated as any – g00dnatur3 Jan 06 '21 at 23:07
  • 1
    @g00dnatur3 is right. If you must use any, then at least specify that it is an array of items of any type. – devaent Nov 23 '21 at 16:16
108

This seems to be some strange behavior in typescript that they are stuck with for legacy reasons. If you have the code:

const result = []

Usually it would be treated as if you wrote:

const result:any[] = []

however, if you have both noImplicitAny FALSE, AND strictNullChecks TRUE in your tsconfig, it is treated as:

const result:never[] = []

This behavior defies all logic, IMHO. Turning on null checks changes the entry types of an array?? And then turning on noImplicitAny actually restores the use of any without any warnings??

When you truly have an array of any, you shouldn't need to indicate it with extra code.

Randy Hudson
  • 1,600
  • 1
  • 12
  • 11
  • 8
    True, this is absolutely unintuitive, a parameter called "no implicit any" should imply that any time something would be assumed to be any - it is not. Also, the implicit "never" seems dumb, why not simply state an error with: Array does not have its type declared. IMHO this should solely depend on noImplicitAny, not on the combination. – DanteTheSmith Feb 17 '21 at 09:49
  • 1
    I think that people who contribute to large repos tend to sometimes over-engineer it. At least we know what flags we should set to make it intuitive for us. As for me I set both flags to true and feel fine with it. – fires3as0n Feb 22 '21 at 15:16
  • Just to clarify, what is changed is not the runtime behavior of the program (there are no types at runtime!). The only thing that changes is the type checker behavior, which becomes a little bit more strict as you enable more checking options in your tsconfig. I don't think it "defies all logic" – Brann Mar 31 '23 at 04:45
104

I got the same error in React function component, using useState hook.

The solution was to declare the type of useState at initialisation using angle brackets:

// Example: type of useState is an array of string
const [items , setItems] = useState<string[]>([]); 
neiya
  • 2,657
  • 4
  • 23
  • 32
32

I was having same error In ReactJS statless function while using ReactJs Hook useState. I wanted to set state of an object array , so if I use the following way

const [items , setItems] = useState([]);

and update the state like this:

 const item = { id : new Date().getTime() , text : 'New Text' };
 setItems([ item , ...items ]);

I was getting error:

Argument of type '{ id: number; text: any }' is not assignable to parameter of type 'never'

but if do it like this,

const [items , setItems] = useState([{}]);

Error is gone but there is an item at 0 index which don't have any data(don't want that).

so the solution I found is:

const [items , setItems] = useState([] as any);
ImFarhad
  • 2,669
  • 2
  • 18
  • 30
30
const foo = (foo: string) => {
  const result: string[] = []
  result.push(foo)
}

You needed specify what the array is since result = [] has a return type of any[]. Typically you want to avoid any types since they are meant to be used as an "Escape hatch" according to Microsoft.

The result is an object that is an array of string.

Nathan Wailes
  • 9,872
  • 7
  • 57
  • 95
Shah
  • 2,126
  • 1
  • 16
  • 21
23

The solution i found was

const [files, setFiles] = useState([] as any);
  • 8
    Using `as any` thwarts a static typing system. If you know what type or types will be housed in the array, it's much better to be explicit: `const myArray: string[] = []; const [files, setFiles] = useState(myArray);`. Note in the case of `useState`, you can pass in a generic, instead: `const [files, setFiles] = useState([]);` – jmealy Oct 01 '20 at 20:00
  • This is a bad practice. By taking `as any` you are just saying "nah I don't want to use typescript". Neiya's answer on the other hand is good enough. A better approach should be interface, but I am new to typescript as well, so I am not sure how to interface this one. – Gogol Jul 03 '21 at 09:20
  • 3
    I can't believe this answer has so many upvotes, this is basically silencing typescript, defeating its purpose altogether. – jperl Oct 04 '21 at 14:14
  • @jmealy your answer worked for me and should be the ts way of solving this. Following your example, I declared a `const` outside my component as `const initialEmailsState: string[] = [];` and used it inside the the component with `useState` as `const [emails, setEmails] = useState(initialEmailsState);` and now I can set `emails` like this without problems: `setEmails([...emails, createOption(inputValue)]);` – Chaiwa Jul 20 '22 at 19:49
  • dont do this. please use generic for element typing. – ZeroCho Jul 30 '22 at 01:36
11

I was able to get past this by using the Array keyword instead of empty brackets:

const enhancers: Array<any> = [];

Use:

if (typeof devToolsExtension === 'function') {
  enhancers.push(devToolsExtension())
}
Mickers
  • 1,367
  • 1
  • 20
  • 28
  • Thanks for pointing out. The `Array` keyword yet is another good way. It is even more semantically useful in case you have to define a type for an array of arrays like this `let parsed: Array<[]> = [];` – Valentine Shi Oct 23 '20 at 08:39
  • @ValentineShi You could still do something like ```[][]```. If you wanted something like an array of array of numbers you could do ```number[][]```. On that note, do consider that: ```parsed: Array<[]>``` here is implicitly ```Array``` – Shah Mar 24 '22 at 15:43
10

Error: Argument of type 'any' is not assignable to parameter of type 'never'.

In tsconfig.json -

  "noImplicitReturns": false,

   "strictNullChecks":false,

enter image description here

Solution: type as 'never'

enter image description here

rohit.khurmi095
  • 2,203
  • 1
  • 14
  • 12
6

Remove "strictNullChecks": true from "compilerOptions" or set it to false in the tsconfig.json file of your Ng app. These errors will go away like anything and your app would compile successfully.

Disclaimer: This is just a workaround. This error appears only when the null checks are not handled properly which in any case is not a good way to get things done.

  • For me,in tsconfig is only "strict" part,when i set it to false as you say error go away,and this is in react,not angular.Thanks. – Goran_Ilic_Ilke Aug 16 '20 at 08:45
5

One more reason for the error.

if you are exporting after wrapping component with connect()() then props may give typescript error
Solution: I didn't explore much as I had the option of replacing connect function with useSelector hook
for example

/* Comp.tsx */
interface IComp {
 a: number
}

const Comp = ({a}:IComp) => <div>{a}</div>

/* ** 

below line is culprit, you are exporting default the return 
value of Connect and there is no types added to that return
value of that connect()(Comp) 

** */

export default connect()(Comp)


--
/* App.tsx */
const App = () => {
/**  below line gives same error 
[ts] Argument of type 'number' is not assignable to 
parameter of type 'never' */
 return <Comp a={3} />
}
Akshay Vijay Jain
  • 13,461
  • 8
  • 60
  • 73
5

I got the error when defining (initialising) an array as follows:

let mainMenu: menuObjectInterface[] | [] = [];

The code I got the problem in:

let mainMenu: menuObjectInterface[] | [] = [];
dbresult.rows.forEach((m) => {
    if (!mainMenu.find((e) => e.menucode === m.menucode)) {
        // Not found in mainMenu, yet
        mainMenu.push({menucode: m.menucode, menudescription: m.menudescription})  // Here the error
    }
})

The error was: TS2322: Type 'any' is not assignable to type 'never'

The reason was that the array was initialised with also the option of an empty array. Typescript saw a push to a type which also can be empty. Hence the error.

Changing the line to this fixed the error:

let mainMenu: menuObjectInterface[] = [];
BertC
  • 2,243
  • 26
  • 33
4

You need to type result to an array of string const result: string[] = [];.

domready
  • 252
  • 1
  • 6
2

you could also add as string[]

const foo = (foo: string) => {
  const result = []
  (result as string[]).push(foo)
}

I did it when it was part of an object

let complexObj = {
arrData : [],
anotherKey: anotherValue
...
}
(arrData as string[]).push('text')
1

in latest versions of angular, you have to define the type of the variables:

  1. if it is a string, you must do like that:

    public message : string ="";

  2. if it is a number:

    public n : number=0;

  3. if a table of string:

    public tab: string[] = [];

  4. if a table of number:

    public tab: number[]=[];

  5. if a mixed table:

    public tab: any[] = []; .......etc (for other type of variables)

  6. if you don't define type of variable: by default the type is never

NB: in your case, you must know the type of variables that your table must contain, and choose the right option (like option 3 ,4 5 ).

Mounir bkr
  • 1,069
  • 6
  • 6
1

In Vue 3 app for typescript supporting , you can define as follows :

const result = ref<string[]>([]);

const foo = (foo:string)=>{
    result.value.push(foo as string)
}
amir tbi
  • 320
  • 2
  • 14
1

I did a workaround by doing

const array = new Array()
array.push(123)
console.log(array) // => [123]
desertnaut
  • 57,590
  • 26
  • 140
  • 166
Nats
  • 31
  • 5
  • It stopped the error on the type, I understand its better to declare the types, but in some extraordinary case, I want some javascript flexibility... – Mark Jul 25 '23 at 14:09
0

This error occurs when you set the value of a property in an object when you haven't set the properties of the object. Declare a type for the object with its properties, then assign the type when you instantiated the object. Now you can set the values of the properties without this error.

Thomas David Kehoe
  • 10,040
  • 14
  • 61
  • 100
0

I had this error for useRef

before with error:

const revealRefs = useRef([]);

  const addToRefs = (el) => {
    if (el && !revealRefs.current.includes(el)) {
      revealRefs.current.push(el);
    }
  };

after without error:

const revealRefs = useRef<HTMLElement[]>([]);

  const addToRefs = (el: HTMLElement | null) => {
    if (el && !revealRefs.current.includes(el)) {
      revealRefs.current.push(el);
    }
  };
atazmin
  • 4,757
  • 1
  • 32
  • 23
0

In case you are using TypeScript with Vue and you are facing this issue in data when initializing the variable. you can try this {} as any.

export default defineComponent({
name: "Student",
 data() {
    return {
       studentList: {} as any,
    }
}
......
})
KushalSeth
  • 3,265
  • 1
  • 26
  • 29