简体   繁体   English

打字稿:对象可能是“未定义”

[英]Typescript: Object is possibly 'undefined'

I'm curious as to why I would be getting a Typescript warning below.我很好奇为什么我会在下面收到 Typescript 警告。

There error appears on this line: a[k].toString().toLowerCase()此行出现错误: a[k].toString().toLowerCase()

However I have the check if (a && a[k]) which should ensure that in the next line, a and a[k] cannot be undefined?但是我检查if (a && a[k])应该确保在下一行中, aa[k]不能未定义?

// Return coins that match text search by currency symbol or name.
export const findAsset = (txt: string, assets: IAsset[] | null[]) => {
  // assets will exist here...
  if (assets) {
    // Typescript error here...
    const checkText = (k: string, a: IAsset | null) => {
      if (a && a[k]) {
        return (textMatch(txt.toLowerCase(), a[k].toString().toLowerCase()) ? a : null);
      }
    }
    const curriedCheckText = R.curry(checkText);
    const byName = R.map(curriedCheckText('name'), assets);
    const bySymbol = R.map(curriedCheckText('currency'), assets);
    const matchNames = R.reject(R.isNil, byName);
    const matchSymbols = R.reject(R.isNil, bySymbol);
    const combinedSearch = (matchNames.concat(matchSymbols));
    return R.uniq(combinedSearch);
  }
  else {
    return [];
  }
};

This is the shape of the IAsset interface这是IAsset界面的形状

export interface IAsset {
  [key: string]: string | number | undefined | boolean;
  availableSupply?: string;
  currency: string;
  exchange: string;
  exchange_base?: string;
  marketCap: number;
  name: string;
  percentage?: number;
  price: number;
  position?: number;
  value?: number;
  inWatchlist?: boolean;
}

在此处输入图像描述

tsconfig tsconfig

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
    "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
    "lib": [
      "dom",
      "es2015",
      "es2016",
      "es2017",
    ], /* Specify library files to be included in the compilation. */,
    "allowJs": true,                       /* Allow javascript files to be compiled. */
    "checkJs": true,                       /* Report errors in .js files. */
    "jsx": "react",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    "sourceMap": true,                     /* Generates corresponding '.map' file. */
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    // "outDir": "./",                        /* Redirect output structure to the directory. */
    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "composite": true,                     /* Enable project compilation */
    // "removeComments": true,                /* Do not emit comments to output. */
    "noEmit": true,                        /* Do not emit outputs. */
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    "resolveJsonModule": true,
    "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    "strict": true /* Enable all strict type-checking options. */,
    "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
    "strictNullChecks": true /* Enable strict null checks. */,
    "strictFunctionTypes": true /* Enable strict checking of function types. */,
    "strictBindCallApply": true /* Enable strict 'bind', 'call', and 'apply' methods on functions. */,
    "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */,
    "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */,
    "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,

    /* Additional Checks */
    // "noUnusedLocals": true,                /* Report errors on unused locals. */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
    // "types": [],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */

    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
  },
  "include": [
    "components/**/*",
    "pages/**/*",
  ],
  "exclude": [
    "node_modules",
    "styles",
    "_document.tsx"
  ]
}

There are two ways to that I can think of to get rid of the error.我可以想到两种方法来摆脱错误。

The first way I can think of is to use a fallback with the ||我能想到的第一种方法是对||使用回退operator, which would turn运营商,这将转向

a[k].toString().toLowerCase()

Into this, so if the value is falsy, then use an empty string.进入这个,所以如果值是假的,那么就使用一个空字符串。

(a[k] || '').toString().toLowerCase()
// Or with optional chaining
a[k]?.toString().toLowerCase() || ''

The other way is to save the value to a variable and check the new variable.另一种方法是将值保存到变量中并检查新变量。 Which then makes this然后使这个

if (a && a[k]) {
  return textMatch(txt.toLowerCase(), a[k].toString().toLowerCase()) ? a : null;
}

Become this:变成这样:

let v = a ? a[k] : null
if (v) {
  return textMatch(txt.toLowerCase(), v.toString().toLowerCase()) ? a : null;
}

Typescript doesn't keep type information about values at specific array indices. Typescript 不保留有关特定数组索引处的值的类型信息。 For example, this is an error:例如,这是一个错误:

function test(a: (number | string)[]) {
    if (typeof a[3] === "number") {
        const num: number = a[3];
    }
}

To get something that can have type information, you could put a[k] into some other variable like this:要获得可以包含类型信息的内容,您可以将a[k]放入其他一些变量中,如下所示:

const checkText = (k: string, a: IAsset | null) => {
if (a) {
  const atK = a[k];
  if (atK) {
    return (textMatch(txt.toLowerCase(), atK.toString().toLowerCase()) ? a : null);
  }
}

or you could cast it, because you know more about the types than the type system:或者你可以转换它,因为你比类型系统更了解类型:

const checkText = (k: string, a: IAsset | null) => {
  if (a && a[k]) {
    return (textMatch(txt.toLowerCase(), (a[k] as string | number | true).toString().toLowerCase()) ? a : null);
  }
}

or you could avoid having to worry about undefineds by using string interpolation:或者您可以通过使用字符串插值来避免担心未定义:

const checkText = (k: string, a: IAsset | null) => {
  if (a && a[k]) {
    return (textMatch(txt.toLowerCase(), `${a[k]}`.toLowerCase()) ? a : null);
  }
}

Ideally the type system would take care of these things, but I'm sure there's some reason why this kind of type information isn't available in general.理想情况下,类型系统会处理这些事情,但我确信这种类型信息通常不可用是有原因的。

Not sure if this is 100% applicable to your question, ever since TypeScript 3.7 is released, the use of optional chaining ( ? operator) is definitely another relevant solution to be explored.不确定这是否 100% 适用于您的问题,自从 TypeScript 3.7 发布以来,使用可选链?运算符)绝对是另一个需要探索的相关解决方案。 You may install the latest stable version of TypeScript:您可以安装最新的稳定版 TypeScript:

npm install typescript

As such, checkText can be simplified by using the optional chaining operator.因此,可以通过使用可选的链接运算符来简化checkText

const checkText = (k: string, a: IAsset | null) => {
  return (textMatch(txt.toLowerCase(), a?.[k].toString().toLowerCase()) ? a : null);
}

Supress the error in VUE templates抑制 VUE 模板中的错误

If you understood the error and want to know how to handle it in VUE templates: simply put a condition in the parent element如果您理解错误并想知道如何在 VUE 模板中处理它:只需在父元素中放置一个条件

<div v-if="user">
   <p>Hallo {{user.firstName}}</p>
</div>

In Angular, i put ngIF and solved the problem for me.在 Angular 中,我放置了 ngIF 并为我解决了这个问题。

<div *ngIf="user" class="row">
<div class="input-field col s6">
  <input
    [(ngModel)]="user.firstName"
    placeholder="Placeholder"
    id="first_name"
    type="text"
    class="validate"
  />
  <label for="first_name">First Name</label>
</div>

You can use !您可以使用 ! so that the error "Object is possibly 'undefined'" no longer occurs.以便不再出现错误“对象可能是'未定义'”。 a[k]!.toString().toLowerCase() a[k]!.toString().toLowerCase()

<ng-container *ngIf="comment.children && comment.children!.length > 0">
    // your code here
</ng-container>

Ok, it looks like the culprit here is the use of "strictNullChecks": true . 好的,罪魁祸首似乎是"strictNullChecks": true的使用"strictNullChecks": true in your config file. 在您的配置文件中。

However I would not recommend removing this flag, this check is actually giving you a valid hint so that can use a better null check in your code. 但是,我不建议您删除此标志,因为此检查实际上为您提供了有效的提示,以便可以在代码中使用更好的null检查。 Instead, I would look into better ways to doing the null or undefined check. 相反,我将研究更好的方法来执行null或未定义的检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM