首页 > 解决方案 > TypeScript 错误 TS1183:无法在环境上下文中声明实现

问题描述

为什么我会收到来自 TS 教程但不会引发错误的相同代码的错误?

从教程(https://www.typescriptlang.org/docs/handbook/namespaces.html#namespacing):

  1. 命名空间。
  2. 命名空间内的接口
  3. 类实现接口
  4. 类实现方法
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;
    const numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

我抛出的几乎相同的代码。

  1. 命名空间。
  2. 命名空间内的接口
  3. 类实现接口
  4. 类实现方法
// index.d.ts

declare namespace LA {
  export interface BelAir {
    populate(): undefined;
  }

  interface Burbank {

  }

  export class BelAirClass implements BelAir {
    populate() {  // Error is thrown here, 
      return undefined
    }
  }

}

// la.ts
import LA from './index';

const ba = new LA.BelAirClass();
const u: undefined = ba.populate();

console.log('[ba]', ba);
console.log('[u]', u);

// CLI
$ npm run tsc la.ts

index.d.ts:11:16 - error TS1183: An implementation cannot be declared in ambient contexts.

标签: typescript

解决方案


您的代码使用declare nampespace,这用于编写声明(通常用于现有的 JS 代码)而无需任何实现。此外,您的代码位于一个d.ts文件中,该文件再次用于为现有 JS 代码编写声明。如果您删除declare并将代码移动到.ts文件中,它将起作用。export如果您想import在另一个文件中的命名空间中添加一个:

// index.ts
export namespace LA {
  export interface BelAir {
    populate(): undefined;
  }

  interface Burbank {

  }

  export class BelAirClass implements BelAir {
    populate() {  // Error is thrown here, 
      return undefined
    }
  }

}

// la.ts
import { LA } from './index';

const ba = new LA.BelAirClass();
const u: undefined = ba.populate();

console.log('[ba]', ba);
console.log('[u]', u);

此外,由于您使用的是模块(即exportimport语法),namespace因此不建议使用,实际上是不好的做法。见GH 评论

归结为:如果您正在考虑使用名称空间进行代码组织:不要。模块已经包含了这个角色。如果您需要只有命名空间才能提供的功能: 做,但要检查没有命名空间(例如,使用类静态或函数属性,或重新导出的模块)来表达概念是否同样具有表达力。在同一个项目中混合命名空间和模块也是一种不好的风格 - 只是感觉不对,因为传统意义上命名空间的主要功能之一是跨文件范围合并,这不会发生在模块之间(因为,如我说,模块本身实际上是一个命名空间)。

所以你的模块代码是:

// index.ts


export interface BelAir {
  populate(): undefined;
}

interface Burbank {

}

export class BelAirClass implements BelAir {
  populate() {  // Error is thrown here, 
    return undefined
  }
}



// la.ts
import * as LA from './index';

const ba = new LA.BelAirClass();
const u: undefined = ba.populate();

console.log('[ba]', ba);
console.log('[u]', u);

推荐阅读