首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果创建库,是否应该手动验证TypeScirpt中的参数?

如果创建库,是否应该手动验证TypeScirpt中的参数?
EN

Stack Overflow用户
提问于 2022-08-19 00:34:38
回答 2查看 155关注 0票数 3

至少知道TypeScript是如何工作的,每个人都可以回答:“是的。TypeScript只是将代码转到JavaScript上,但没有添加任何额外的行为,包括在执行过程中的类型检查。”例如,

代码语言:javascript
复制
function example(parameter: string): void {
  console.log(parameter.charAt(1));
}

将转到:

代码语言:javascript
复制
"use strict";
function example(parameter) {
  console.log(parameter.charAt(1));
}

如果JavaScript用户将调用example(3),则将引发错误Uncaught TypeError: parameter.charAt is not a function

好吧,如果我明白我为什么要问这个问题?因为我将花费数十个小时来改进我的库(@yamato-daiwa/es-分机)),但更重要的是,将库大小增加多倍。不是夸大其词。例如,对于1.6.x版本,addElementsToArray函数非常简单,没有依赖关系:

代码语言:javascript
复制
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;
}

一旦我用类型检查改进了它,它就变成了:

代码语言:javascript
复制
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%的功能行。库的可分发性将因多种类型而变得更重,这对于前端应用程序来说至关重要,因为在前端应用程序中,每千字节都是计数的。

上面的检查还不够细致!此外,我们可以:

  • 当所需的可选命名参数(toStarttoEndtoPosition__numerationFrom0toPosition__numerationFrom1)超过1时,请检查其中哪些参数确实已被传递,并记录它们的名称。
  • 拆分这些参数类型的检查,检查这些参数中没有一个通过(目前正在同时执行这两个检查)
  • 如果上述参数具有不正确的子类型(例如,如果toStarttoEnd具有false值,或者toPosition__numerationFrom0toPosition__numerationFrom1为负数或小数),则分别对其进行记录。

潜在的虚假问题

简而言之,我可以由非类型记录用户报告无效参数类型引起的错误,但是如果TypeScript编写了相同的代码,TypeScript就会发出错误。最终可以清楚地看出,这一问题是由于与JavaScript的结合而不是TypeScript的无效参数类型所造成的,调查、交谈等都会浪费时间,而且可能是大量的此类问题实际上就是无效的TypeScript。

赏金之际的最新情况

这个问题已经得到了回答,但是由于参数验证,我的库的大小在未来可能会增加很多倍,这让我感到困扰。为了解决这个问题,我需要有人告诉我:“你做的是对的,继续做下去!如果由于参数验证,分布者的规模增加了多次,对于前端应用程序来说,这一点都不重要。”或者“如果是因为参数的验证,那么助手库的大小就不好了。您应该跳过参数验证以保持库的苗条”。由高级/硕士网页开发人员提供。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-08-19 00:45:17

在系统面向客户的边缘进行验证是一种很好的实践。

在开始的时候,所有的清喉代码都可以被看作是一件好事,使这些功能的主体更加简单和自信地编写。

当然,您还可以通过查找或构建断言库来缩小代码。

票数 3
EN

Stack Overflow用户

发布于 2022-10-31 21:20:03

你似乎把两个不同的问题混为一谈。一方面,您可以输入用户正在访问的接口(例如函数签名),这允许TypeScript客户端验证函数调用是用适当的值进行的,并且是模块很好地处理TypeScript项目所必需的。另一方面,您需要对接口进行验证,对每个输入进行编程检查,以确保其具有适当的类型和值。

通常是TypeScript的最大优点之一,就是这些编程检查是不必要的。

我要提醒您不要验证每一个输入,就像您在示例中所做的那样。这并不能保证你总是会阻止所有不允许的值,而且在“每千字节计数”的情况下,你也想避免做大量的检查,而这些检查在任何地方都可能是不必要的。在用户输入的情况下,该模块的许多用户将在数据传递给您的代码之前验证它们的数据。

此外,更长和更复杂的代码将更难维护,更慢地添加新的功能。它也更有可能开发bug。可能有几个地方允许无效的值通过会造成严重的损害,特别是向这些地方添加检查是很好的做法,但是如果有人将错误的参数传递给列表操作函数,然后得到一个错误,那就不是世界末日了。

您最好把时间花在为那些使用JavaScript模块的人编写好的文档上。作为一个额外的优势,这个文档还可以帮助TypeScript用户。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73410742

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档