admin管理员组文章数量:1356891
I am new to TypeScript and have just started migrating my application from JavaScript to TypeScript.
- First function:
calcAvg
, takes an array of numbers and returns their average. - Second function:
avgRoasDiscrepancy
, takes two arrays, if the two arrays are of equal length and with no null values, it will subtract each element from one list with the element in the same index from the second array.
The issue is in the following map
function (see full code below):
const discArray = clientRoasArray.map((value: number, index: number) => value - roasArray[index]);
I get the following error:
Argument of type '(value: number, index: number) => number' is not assignable to parameter of type '(value: number | null, index: number, array: (number | null)[]) => number'.
Types of parameters 'value' and 'value' are inpatible.
Type 'number | null' is not assignable to type 'number'.
Type 'null' is not assignable to type 'number'
I don't know how to "convince" TypeScript that both value
and roasArray[index]
are in fact numbers and not nulls.
Here is the plete code :
interface DailyData {
id: number
clientCost:number
conValue:number
clientConvValue:number
margin: number
}
const calcAvg = (dataList: number[]) => {
const reducer = (accumulator: number, curr: number) => accumulator + curr;
const dataSum = dataList.reduce(reducer, 0);
return dataSum / dataList.length;
};
const avgRoasDiscrepancy = (advertiserStats: DailyData[]) => {
const clientRoasArray = advertiserStats.map((obj: DailyData) => obj.clientCost > 0 ? obj.clientConvValue/obj.clientCost: null);
const roasArray = advertiserStats.map((obj: DailyData) => obj.clientCost > 0 ? obj.conValue/obj.clientCost: null);
if (clientRoasArray.length === 0 || roasArray.length === 0) {
return 'no data'
}
if (!!clientRoasArray.every((el: number|null) => el!== null) || (!roasArray.every((el: number|null) => el!== null) )) {
//if one of the arrays has null values don't calculate
return 'no data';
}
if (clientRoasArray.length === roasArray.length) {
const discArray = clientRoasArray.map((value: number, index: number) => value - roasArray[index]);
return calcAvg(discArray as number[]);
}
return 'no data';
};
I am new to TypeScript and have just started migrating my application from JavaScript to TypeScript.
- First function:
calcAvg
, takes an array of numbers and returns their average. - Second function:
avgRoasDiscrepancy
, takes two arrays, if the two arrays are of equal length and with no null values, it will subtract each element from one list with the element in the same index from the second array.
The issue is in the following map
function (see full code below):
const discArray = clientRoasArray.map((value: number, index: number) => value - roasArray[index]);
I get the following error:
Argument of type '(value: number, index: number) => number' is not assignable to parameter of type '(value: number | null, index: number, array: (number | null)[]) => number'.
Types of parameters 'value' and 'value' are inpatible.
Type 'number | null' is not assignable to type 'number'.
Type 'null' is not assignable to type 'number'
I don't know how to "convince" TypeScript that both value
and roasArray[index]
are in fact numbers and not nulls.
Here is the plete code :
interface DailyData {
id: number
clientCost:number
conValue:number
clientConvValue:number
margin: number
}
const calcAvg = (dataList: number[]) => {
const reducer = (accumulator: number, curr: number) => accumulator + curr;
const dataSum = dataList.reduce(reducer, 0);
return dataSum / dataList.length;
};
const avgRoasDiscrepancy = (advertiserStats: DailyData[]) => {
const clientRoasArray = advertiserStats.map((obj: DailyData) => obj.clientCost > 0 ? obj.clientConvValue/obj.clientCost: null);
const roasArray = advertiserStats.map((obj: DailyData) => obj.clientCost > 0 ? obj.conValue/obj.clientCost: null);
if (clientRoasArray.length === 0 || roasArray.length === 0) {
return 'no data'
}
if (!!clientRoasArray.every((el: number|null) => el!== null) || (!roasArray.every((el: number|null) => el!== null) )) {
//if one of the arrays has null values don't calculate
return 'no data';
}
if (clientRoasArray.length === roasArray.length) {
const discArray = clientRoasArray.map((value: number, index: number) => value - roasArray[index]);
return calcAvg(discArray as number[]);
}
return 'no data';
};
Share
Improve this question
edited Jan 24, 2022 at 18:35
Youssouf Oumar
46.6k16 gold badges103 silver badges105 bronze badges
asked Jan 24, 2022 at 18:16
LimorLimor
1291 gold badge3 silver badges8 bronze badges
3 Answers
Reset to default 3In this line
const clientRoasArray = advertiserStats.map((obj: DailyData) => obj.clientCost > 0 ? obj.clientConvValue/obj.clientCost: null);
You are assuming that the elements of clientRoasArray could be number
or could be null
and this is clear in your condition : null
And in this line, you are identifying the value of the clientRoasArray
as number only
which is wrong because you told your code that the value could be number|null
All you need is to change this line
const discArray = clientRoasArray.map((value: number, index: number) => value - roasArray[index]);
to this
const discArray = clientRoasArray.map((value: number | null, index: number) => value - roasArray[index]);
but you will face an issue with roasArray[index]
because it also could be null
I wasn't able to get type inference to work properly using the every
calls on the arrays, however you can make a type guard to help the piler understand that the arrays are of type number[]
instead of (number | null)[]
. This will also help with refactoring a bit.
Note that there's also an issue with your current type checking logic, but looks like it's just a typo: the !!
before the first condition should just be a single !
.
Here's a simple type guard:
function isNonNullNumberArray(x: (number | null)[]): x is number[] {
return x.every(e => e !== null);
}
Then you can use isNonNullNumberArray
like this:
if (!(isNonNullNumberArray(clientRoasArray) && isNonNullNumberArray(roasArray))) {
//if one of the arrays has null values don't calculate
return 'no data';
}
// now the piler knows that neither array contains null values
if (clientRoasArray.length === roasArray.length) {
const discArray = clientRoasArray.map((value: number, index: number) => value - roasArray[index]);
return calcAvg(discArray);
}
return 'no data';
You could make a more general type guard like this too if you wanted using generics so that it works for types other than number
:
function isNonNullArray<T>(x: T[]): x is Exclude<T, null>[] {
return x.every(e => e !== null);
}
By the way, you don't need to explicitly declare parameter types in functions passed to map
and other array method as the piler can infer the types based on the signature of the array method (e.g. map
).
You could check if your variable is not null
and use !
(non-null assertion operator) to tell TypeScript the expression can not be null
. Also the type for value
is number | null
.
if (clientRoasArray.length === roasArray.length) {
const discArray = clientRoasArray.map((value: number | null, index: number) => {
return value && roasArray[index] ? value - roasArray[index]! : null
});
return calcAvg(discArray as number[]);
}
本文标签: javascriptJS to TS Type 39null39 is not assignable to type 39number39Stack Overflow
版权声明:本文标题:javascript - JS to TS: Type 'null' is not assignable to type 'number' - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1743996614a2573104.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论