【发布时间】:2022-11-10 01:02:26
【问题描述】:
至少大致了解 TypeScript 是如何工作的,每个人都可以回答:“是的。TypeScript 只是将代码转换为 JavaScript,但没有添加任何额外的行为,包括执行期间的类型检查。”例如,
function example(parameter: string): void {
console.log(parameter.charAt(1));
}
将被转译为:
"use strict";
function example(parameter) {
console.log(parameter.charAt(1));
}
如果 JavaScript 用户调用example(3),则会抛出错误Uncaught TypeError: parameter.charAt is not a function。
好吧,如果我明白这一点,为什么我要问这个问题?因为我要花几十个小时来改进我的库(@yamato-daiwa/es-extensions),但更重要的是,将库大小增加了数倍。这并不夸张。例如,对于 1.6.x 版本,addElementsToArray 函数非常简单:
export default function addElementsToArray<ArrayElement>(
namedParameters:
{
targetArray: Array<ArrayElement>;
newElements: Array<ArrayElement>;
mutably: boolean;
} &
(
{ toStart: true; } |
{ toEnd: true; } |
{ toPosition__numerationFrom0: number; } |
{ toPosition__numerationFrom1: number; }
)
): Array<ArrayElement> {
const workpiece: Array<ArrayElement> = namedParameters.mutably ?
namedParameters.targetArray : [ ...namedParameters.targetArray ];
if ("toStart" in namedParameters) {
workpiece.unshift(...namedParameters.newElements);
return workpiece;
}
if ("toEnd" in namedParameters) {
workpiece.push(...namedParameters.newElements);
return workpiece;
}
const positionOfFirstNewElement__numerationFrom0: number = "toPosition__numerationFrom0" in namedParameters ?
namedParameters.toPosition__numerationFrom0 : namedParameters.toPosition__numerationFrom1 - 1;
workpiece.splice(positionOfFirstNewElement__numerationFrom0, 0, ...namedParameters.newElements);
return workpiece;
}
一旦我通过类型检查对其进行了改进,它就变成了:
import Logger from "../Logging/Logger";
import InvalidParameterValueError from "../Errors/InvalidParameterValue/InvalidParameterValueError";
import IncompatiblePropertiesInObjectTypeParameterError from
"../Errors/IncompatiblePropertiesInObjectTypeParameter/IncompatiblePropertiesInObjectTypeParameterError";
import stringifyAndFormatArbitraryValue from "../Strings/stringifyAndFormatArbitraryValue";
import isArbitraryObject from "../TypeGuards/Objects/isArbitraryObject";
import isNotUndefined from "../TypeGuards/Nullables/isNotUndefined";
import isNonNegativeInteger from "../TypeGuards/Numbers/isNonNegativeInteger";
import isNaturalNumber from "../TypeGuards/Numbers/isNaturalNumber";
export default function addElementsToArray<ArrayElement>(
namedParameters:
Readonly<
(
{
mutably: true;
targetArray: Array<ArrayElement>;
} |
{
mutably: false;
targetArray: ReadonlyArray<ArrayElement>;
}
) &
{
newElements: ReadonlyArray<ArrayElement>;
toStart?: true;
toEnd?: true;
toPosition__numerationFrom0?: number;
toPosition__numerationFrom1?: number;
}
>
): Array<ArrayElement> {
if (!isArbitraryObject(namedParameters)) {
Logger.throwErrorAndLog({
errorInstance: new InvalidParameterValueError({
parameterNumber: 1,
parameterName: "namedParameters",
messageSpecificPart: "The first and only parameter of 'addElementsToArray' must be of the object type."
}),
title: InvalidParameterValueError.localization.defaultTitle,
occurrenceLocation: "addElementsToArray(namedParameters)"
});
}
if (!Array.isArray(namedParameters.targetArray)) {
Logger.throwErrorAndLog({
errorInstance: new InvalidParameterValueError({
parameterName: "namedParameters",
parameterNumber: 1,
messageSpecificPart: "The 'targetArray' is not the valid array and has value:\n" +
`${ stringifyAndFormatArbitraryValue(namedParameters.targetArray) }`
}),
title: InvalidParameterValueError.localization.defaultTitle,
occurrenceLocation: "addElementsToArray(namedParameters)"
});
}
const alternativelyRequestOptions: Array<true | number> = [
namedParameters.toStart,
namedParameters.toEnd,
namedParameters.toPosition__numerationFrom0,
namedParameters.toPosition__numerationFrom1
].filter(isNotUndefined);
if (alternativelyRequestOptions.length > 1) {
Logger.logError({
errorType: IncompatiblePropertiesInObjectTypeParameterError.NAME,
title: IncompatiblePropertiesInObjectTypeParameterError.localization.defaultTitle,
description: "Exactly one of 'toStart', 'toEnd', 'toPosition__numerationFrom0', 'toPosition__numerationFrom1' " +
"must be specified while actually multiple of them has been. No elements will be added to target array.",
occurrenceLocation: "addElementsToArray(namedParameters)"
});
return namedParameters.targetArray;
}
const workpiece: Array<ArrayElement> = namedParameters.mutably ?
namedParameters.targetArray : [ ...namedParameters.targetArray ];
if (namedParameters.toStart === true) {
workpiece.unshift(...namedParameters.newElements);
return workpiece;
}
if (namedParameters.toEnd === true) {
workpiece.push(...namedParameters.newElements);
return workpiece;
}
let positionOfFirstNewElement__numerationFrom0: number;
if (isNonNegativeInteger(namedParameters.toPosition__numerationFrom0)) {
positionOfFirstNewElement__numerationFrom0 = namedParameters.toPosition__numerationFrom0;
} else if (isNaturalNumber(namedParameters.toPosition__numerationFrom1)) {
positionOfFirstNewElement__numerationFrom0 = namedParameters.toPosition__numerationFrom1 - 1;
} else {
Logger.logError({
errorType: InvalidParameterValueError.NAME,
title: InvalidParameterValueError.localization.defaultTitle,
description: alternativelyRequestOptions.length === 0 ?
"None one of 'toStart', 'toEnd', 'toPosition__numerationFrom0', 'toPosition__numerationFrom1' has been specified." :
(
"The specified value of 'toStart', 'toEnd', 'toPosition__numerationFrom0' or 'toPosition__numerationFrom1' has " +
"invalid type, value or numbers set."
) +
"No elements will be added to target array.",
occurrenceLocation: "addElementsToArray(namedParameters)"
});
return namedParameters.targetArray;
}
workpiece.splice(positionOfFirstNewElement__numerationFrom0, 0, ...namedParameters.newElements);
return workpiece;
}
在这种情况下,验证需要大约一半的行,并且还出现了很多依赖项。有时,验证可以超过 90% 的功能线。可分发的库将变得更重,这对于每千字节都在计数的前端应用程序至关重要。
【问题讨论】:
-
您可以执行验证,也可以期望使用该库的每个人都将以类型感知的方式使用它。 (如果我使用与图书馆文档所说的不同的调用签名,我完全希望我使用的图书馆会破坏 - 那就是我的错,不是图书馆的错,IMO)
-
我的意思是,它不仅仅是在 TypeScript 中。如果您使用 JavaScript 编写它,则必须进行相同的验证。
标签: typescript