não é possível redeclarar variável com escopo de bloco (texto digitado)


99

Estou construindo um aplicativo de nó e, dentro de cada arquivo .js, costumava fazer isso para exigir em vários pacotes.

let co = require("co");

Mas conseguindo

insira a descrição da imagem aqui

etc. Portanto, usando o texto digitado, parece que só pode haver uma declaração / solicitação em todo o projeto? Estou confuso sobre isso, pois pensei que letera o escopo do arquivo atual.

Acabei de ter um projeto que estava funcionando, mas depois de uma refatoração, agora estou recebendo esses erros por todo o lugar.

Alguém pode explicar?


1
Que tal isso - deixe co_module = require ("co"); Enfrentei algo semelhante e isso resolveu o erro.
tirião de

1
Este parece ser um bug de digitação. Fiz um exemplo mínimo aqui: gist.github.com/rjmunro/428ec644b6e53a499ca3a5ba8de2edc7
rjmunro

5
2,5 anos depois e estou de volta à minha própria pergunta, isso ainda é um problema. desta vez com o nó integrado. const fs = require('fs')dá um erro semelhante, então não tenho certeza de qual biblioteca importar isso ...
dcsan

O fato de que TS ainda faz isso é ridículo
GN.

Respostas:


67

Em relação ao próprio erro, leté usado para declarar variáveis locais que existem em escopos de bloco em vez de escopos de função. Também é mais rígido do que var, então você não pode fazer coisas como esta:

if (condition) {
    let a = 1;
    ...
    let a = 2;
}

Observe também que as casecláusulas dentro dos switchblocos não criam seus próprios escopos de bloco, portanto, você não pode declarar novamente a mesma variável local em vários cases sem usar {}para criar um bloco cada.


Quanto à importação, provavelmente você está recebendo este erro porque o TypeScript não reconhece seus arquivos como módulos reais e, aparentemente, as definições de nível de modelo acabam sendo definições globais para ele.

Tente importar um módulo externo do modo ES6 padrão , que não contém nenhuma atribuição explícita e deve fazer o TypeScript reconhecer seus arquivos corretamente como módulos:

import * as co from "./co"

Isso ainda resultará em um erro de compilação se você já tiver algo nomeado co, conforme o esperado. Por exemplo, isso vai ser um erro:

import * as co from "./co"; // Error: import definition conflicts with local definition
let co = 1;

Se você estiver recebendo um erro "não é possível encontrar o módulo co" ...

TypeScript está executando a verificação de tipo completa em relação aos módulos, portanto, se você não tiver definições de TS para o módulo que está tentando importar (por exemplo, porque é um módulo JS sem arquivos de definição), você pode declarar seu módulo em um .d.tsarquivo de definição que não não contém exportações em nível de módulo:

declare module "co" {
    declare var co: any;
    export = co;
}

9
isso dá "impossível encontrar o módulo co". Eu também tentei o typings install coque dá Unable to find "co" in the registry. alguma outra ideia?
DCSAN

Estou tendo o mesmo problema que @dcsan, ele diz que não consegue encontrar o módulo, embora eu claramente tenha o npm instalado.
justin.m.chase

Pode ser causado pelo caminho relativo. Não estou familiarizado com o gerenciamento de módulo NodeJS, mas no RequireJS se os módulos forem referenciados de forma relativa, a pasta atual deve ser explicitamente indicada. Ou seja, em ./covez de co, se co.ts estiver na mesma pasta (ou na saída compilada, co.js).
John Weisz

1
esteja atento, "* as xxx" é importante. Portanto, não "importar xxx de ...", mas "importar * como xxx de ..."
Nurbol Alpysbayev

27

A melhor explicação que consegui foi do post de Tamas Piro .

TLDR; TypeScript usa tipificações DOM para o ambiente de execução global. No seu caso, há uma propriedade 'co' no objeto janela global.

Para resolver isso:

  1. Renomeie a variável ou
  2. Use módulos TypeScript e adicione uma exportação vazia {}:
export {};

ou

  1. Configure as opções do compilador, não adicionando tipificações DOM:

Edite tsconfig.json no diretório do projeto TypeScript.

{
    "compilerOptions": {
        "lib": ["es6"]
      }
}

isso é para o lado do cliente? meu problema original era com o código do lado do servidor e não acredito que as opções do compilador DOM estivessem sendo usadas (projeto antigo)
dcsan

1
Eu confirmo que adicionar export {}resolveu o problema para mim, entretanto adicionar "compilerOptions": { "lib": ["es6"] }NÃO parece ajudar nem durante a compilação nem no VSCode.
adamsfamily

O link para a postagem original está morto.
Cyclonecode

13

Eu estava recebendo este erro semelhante ao compilar meu aplicativo Node.JS Typescript:

node_modules/@types/node/index.d.ts:83:15 - error TS2451: Cannot redeclare block-scoped variable 'custom'.

A solução foi remover este:

"files": [
  "./node_modules/@types/node/index.d.ts"
]

e substituí-lo por este:

"compilerOptions": {
  "types": ["node"]
}

9

Use IIFE(Immediately Invoked Function Expression), IIFE

(function () {
    all your code is here...

 })();

Simples. Funciona perfeitamente. Obrigado! (No meu caso, eu estava declarando const expect = chai.expect;para usar os testes Cucumber no projeto Angular 5).
Maxime Lafarie

7

Para aqueles que vêm aqui nesta era, aqui está uma solução simples para esse problema. Pelo menos funcionou para mim no backend. Eu não verifiquei com o código do frontend.

Basta adicionar:

export {};

no topo do seu código.

Crédito para EUGENE MURAVITSKY


1

Eu tenho o mesmo problema, e minha solução é a seguinte:

// *./module1/module1.ts*
export module Module1 {
    export class Module1{
        greating(){ return 'hey from Module1'}
    }
}


// *./module2/module2.ts*
import {Module1} from './../module1/module1';

export module Module2{
    export class Module2{
        greating(){
            let m1 = new Module1.Module1()
            return 'hey from Module2 + and from loaded Model1: '+ m1.greating();
        }
    }
}

Agora podemos usá-lo no lado do servidor:

// *./server.ts*
/// <reference path="./typings/node/node.d.ts"/>
import {Module2} from './module2/module2';

export module Server {
    export class Server{
        greating(){
            let m2 = new Module2.Module2();
            return "hello from server & loaded modules: " + m2.greating();
        }
    }
}

exports.Server = Server;

// ./app.js
var Server = require('./server').Server.Server;
var server = new Server();
console.log(server.greating());

E do lado do cliente também:

// *./public/javscripts/index/index.ts*

import {Module2} from './../../../module2/module2';

document.body.onload = function(){
    let m2 = new Module2.Module2();
    alert(m2.greating());
}

// ./views/index.jade
extends layout

block content
  h1= title
  p Welcome to #{title}
  script(src='main.js')
  //
    the main.js-file created by gulp-task 'browserify' below in the gulpfile.js

E, claro, um arquivo gulp para tudo isso:

// *./gulpfile.js*
var gulp = require('gulp'),
    ts = require('gulp-typescript'),
    runSequence = require('run-sequence'),
    browserify = require('gulp-browserify'),
    rename = require('gulp-rename');

gulp.task('default', function(callback) {

    gulp.task('ts1', function() {
        return gulp.src(['./module1/module1.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./module1'))
    });

    gulp.task('ts2', function() {
        return gulp.src(['./module2/module2.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./module2'))
    });

    gulp.task('ts3', function() {
        return gulp.src(['./public/javascripts/index/index.ts'])
            .pipe(ts())
            .pipe(gulp.dest('./public/javascripts/index'))
    });

    gulp.task('browserify', function() {
        return gulp.src('./public/javascripts/index/index.js', { read: false })
            .pipe(browserify({
                insertGlobals: true
            }))
            .pipe(rename('main.js'))
            .pipe(gulp.dest('./public/javascripts/'))
    });

    runSequence('ts1', 'ts2', 'ts3', 'browserify', callback);
})

Atualizada. Obviamente, não é necessário compilar arquivos de tipo type separadamente. runSequence(['ts1', 'ts2', 'ts3'], 'browserify', callback)funciona perfeito.


7
Apenas no caso de alguém se afastar do TypeScript pela verbosidade e repetitividade daquele arquivo gulp, ninguém faz isso.
Daniel Earwicker

0

Recebi este erro ao atualizar

gulp-typescript 3.0.2 → 3.1.0

Colocar de volta para 3.0.2 corrigiu


0

No meu caso, o seguinte tsconfig.jsonproblema foi resolvido:

{
  "compilerOptions": {
    "esModuleInterop": true,
    "target": "ES2020",
    "moduleResolution": "node"
  }
}

Não deve haver nenhum type: moduleem package.json.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.