master f1e40c10e31b cached
122 files
334.3 KB
125.8k tokens
17 symbols
1 requests
Download .txt
Showing preview only (363K chars total). Download the full file or copy to clipboard to get everything.
Repository: jkchao/typescript-book-chinese
Branch: master
Commit: f1e40c10e31b
Files: 122
Total size: 334.3 KB

Directory structure:
gitextract_e5a6gj6_/

├── .all-contributorsrc
├── .gitattributes
├── .github/
│   └── workflows/
│       └── gh-pages.yml
├── .gitignore
├── .huskyrc.js
├── .prettierrc
├── LICENSE
├── README.md
├── commitlint.config.js
├── docs/
│   ├── .vuepress/
│   │   ├── config.js
│   │   ├── public/
│   │   │   └── manifest.json
│   │   └── theme/
│   │       ├── components/
│   │       │   ├── Ads.vue
│   │       │   ├── AlgoliaSearchBox.vue
│   │       │   ├── DropdownLink.vue
│   │       │   ├── DropdownTransition.vue
│   │       │   ├── Home.vue
│   │       │   ├── NavLink.vue
│   │       │   ├── NavLinks.vue
│   │       │   ├── Navbar.vue
│   │       │   ├── Page.vue
│   │       │   ├── Sidebar.vue
│   │       │   ├── SidebarButton.vue
│   │       │   ├── SidebarGroup.vue
│   │       │   ├── SidebarLink.vue
│   │       │   └── SidebarLinks.vue
│   │       ├── global-components/
│   │       │   └── Badge.vue
│   │       ├── index.js
│   │       ├── layouts/
│   │       │   ├── 404.vue
│   │       │   └── Layout.vue
│   │       ├── styles/
│   │       │   ├── arrow.styl
│   │       │   ├── code.styl
│   │       │   ├── custom-blocks.styl
│   │       │   ├── mobile.styl
│   │       │   ├── theme.styl
│   │       │   ├── toc.styl
│   │       │   └── wrapper.styl
│   │       └── util/
│   │           └── index.js
│   ├── README.md
│   ├── compiler/
│   │   ├── ast.md
│   │   ├── binder.md
│   │   ├── checker.md
│   │   ├── emitter.md
│   │   ├── overview.md
│   │   ├── parser.md
│   │   ├── program.md
│   │   └── scanner.md
│   ├── error/
│   │   ├── common.md
│   │   └── interpreting.md
│   ├── faqs/
│   │   ├── class.md
│   │   ├── commandline-behavior.md
│   │   ├── comments.md
│   │   ├── common-bug-not-bugs.md
│   │   ├── common-feature-request.md
│   │   ├── decorators.md
│   │   ├── enums.md
│   │   ├── function.md
│   │   ├── generics.md
│   │   ├── glossary-and-terms.md
│   │   ├── jsx-and-react.md
│   │   ├── modules.md
│   │   ├── thing-that-dont-work.md
│   │   ├── tsconfig-behavior.md
│   │   ├── type-guards.md
│   │   └── type-system-behavior.md
│   ├── jsx/
│   │   ├── nonReactJSX.md
│   │   ├── reactJSX.md
│   │   └── support.md
│   ├── new/
│   │   ├── typescript-3.7.md
│   │   ├── typescript-3.8.md
│   │   └── typescript-3.9.md
│   ├── project/
│   │   ├── compilationContext.md
│   │   ├── declarationspaces.md
│   │   ├── dynamicImportExpressions.md
│   │   ├── modules.md
│   │   └── namespaces.md
│   ├── tips/
│   │   ├── avoidExportDefault.md
│   │   ├── barrel.md
│   │   ├── bind.md
│   │   ├── buildToggles.md
│   │   ├── classAreUseful.md
│   │   ├── covarianceAndContravariance.md
│   │   ├── createArrays.md
│   │   ├── curry.md
│   │   ├── functionParameters.md
│   │   ├── infer.md
│   │   ├── lazyObjectLiteralInitialization.md
│   │   ├── limitPropertySetters.md
│   │   ├── metadata.md
│   │   ├── nominalTyping.md
│   │   ├── outFileCaution.md
│   │   ├── singletonPatern.md
│   │   ├── statefulFunctions.md
│   │   ├── staticConstructors.md
│   │   ├── stringBasedEmuns.md
│   │   ├── truthy.md
│   │   ├── typeInstantiation.md
│   │   └── typesafeEventEmitter.md
│   └── typings/
│       ├── ambient.md
│       ├── callable.md
│       ├── discrominatedUnion.md
│       ├── enums.md
│       ├── exceptionsHanding.md
│       ├── freshness.md
│       ├── functions.md
│       ├── generices.md
│       ├── indexSignatures.md
│       ├── interfaces.md
│       ├── lib.md
│       ├── literals.md
│       ├── migrating.md
│       ├── mixins.md
│       ├── movingTypes.md
│       ├── neverType.md
│       ├── overview.md
│       ├── readonly.md
│       ├── thisType.md
│       ├── typeAssertion.md
│       ├── typeCompatibility.md
│       ├── typeGuard.md
│       ├── typeInference.md
│       └── types.md
└── package.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .all-contributorsrc
================================================
{
  "projectName": "typescript-book-chinese",
  "projectOwner": "jkchao",
  "repoType": "github",
  "repoHost": "https://github.com",
  "files": [
    "README.md"
  ],
  "imageSize": 64,
  "commit": false,
  "contributors": [
    {
      "login": "jkchao",
      "name": "三毛",
      "avatar_url": "https://avatars3.githubusercontent.com/u/22933931?v=4",
      "profile": "https://jkchao.cn",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "KnorienChang",
      "name": "KnorienChang",
      "avatar_url": "https://avatars3.githubusercontent.com/u/22536347?v=4",
      "profile": "https://github.com/KnorienChang",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "magic-akari",
      "name": "阿卡琳",
      "avatar_url": "https://avatars0.githubusercontent.com/u/7829098?v=4",
      "profile": "https://github.com/magic-akari",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "hopalay",
      "name": "hopalay",
      "avatar_url": "https://avatars1.githubusercontent.com/u/2362335?v=4",
      "profile": "https://github.com/hopalay",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "S1ngS1ng",
      "name": "Xing Liu",
      "avatar_url": "https://avatars1.githubusercontent.com/u/13592559?v=4",
      "profile": "http://singsing.io/blog",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "chenwangji",
      "name": "chenwangji",
      "avatar_url": "https://avatars1.githubusercontent.com/u/23144765?v=4",
      "profile": "https://github.com/chenwangji",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "helloforrestworld",
      "name": "老农爱盐碱地",
      "avatar_url": "https://avatars3.githubusercontent.com/u/28107509?v=4",
      "profile": "https://github.com/helloforrestworld",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "itxuye",
      "name": "Necros",
      "avatar_url": "https://avatars2.githubusercontent.com/u/9589686?v=4",
      "profile": "http://www.itxuye.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "XuToTo",
      "name": "Xu Jihan",
      "avatar_url": "https://avatars1.githubusercontent.com/u/8039013?v=4",
      "profile": "https://xutoto.im",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Yiiu",
      "name": "Yu",
      "avatar_url": "https://avatars0.githubusercontent.com/u/7876498?v=4",
      "profile": "https://wanan.me/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "YogaLin",
      "name": "Yoga Lin",
      "avatar_url": "https://avatars0.githubusercontent.com/u/11386122?v=4",
      "profile": "https://github.com/YogaLin",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "galenjiang",
      "name": "G",
      "avatar_url": "https://avatars2.githubusercontent.com/u/12699258?v=4",
      "profile": "http://galenjiang.github.io",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Undrum",
      "name": "Undrum",
      "avatar_url": "https://avatars3.githubusercontent.com/u/37131109?v=4",
      "profile": "https://github.com/Undrum",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "zongzi531",
      "name": "Zong",
      "avatar_url": "https://avatars2.githubusercontent.com/u/22429236?v=4",
      "profile": "https://zongzi531.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "LXVC",
      "name": "LXVC",
      "avatar_url": "https://avatars0.githubusercontent.com/u/12185175?v=4",
      "profile": "http://lxvc.github.io",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "jinrichardJIN",
      "name": "Whale",
      "avatar_url": "https://avatars0.githubusercontent.com/u/20592013?v=4",
      "profile": "https://github.com/jinrichardJIN",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "getdaydream",
      "name": "getdaydream",
      "avatar_url": "https://avatars2.githubusercontent.com/u/23274794?v=4",
      "profile": "https://github.com/getdaydream",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "onlyling",
      "name": "Ling ZiQing",
      "avatar_url": "https://avatars3.githubusercontent.com/u/9999765?v=4",
      "profile": "https://www.onlyling.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "izayl",
      "name": "izayl",
      "avatar_url": "https://avatars0.githubusercontent.com/u/10740043?v=4",
      "profile": "https://github.com/izayl",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "shenzekun",
      "name": "Moorez",
      "avatar_url": "https://avatars1.githubusercontent.com/u/21151080?v=4",
      "profile": "http://shenzekun.cn/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "yepbug",
      "name": "萤火之未",
      "avatar_url": "https://avatars3.githubusercontent.com/u/26736658?v=4",
      "profile": "https://github.com/yepbug",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "xfields",
      "name": "xfields",
      "avatar_url": "https://avatars1.githubusercontent.com/u/6301070?v=4",
      "profile": "https://github.com/xfields",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "ZhaZhengRefn",
      "name": "ZhaZheng",
      "avatar_url": "https://avatars0.githubusercontent.com/u/16488686?v=4",
      "profile": "https://segmentfault.com/u/zhazhengrefn",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "dickeylth",
      "name": "弘树@阿里",
      "avatar_url": "https://avatars1.githubusercontent.com/u/2196373?v=4",
      "profile": "http://webminer.js.org",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "dalphyx",
      "name": "wangjingchao",
      "avatar_url": "https://avatars2.githubusercontent.com/u/1576121?v=4",
      "profile": "https://github.com/dalphyx",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "IWANABETHATGUY",
      "name": "IWANABETHATGUY",
      "avatar_url": "https://avatars1.githubusercontent.com/u/17974631?v=4",
      "profile": "https://github.com/IWANABETHATGUY",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "PaytonTang",
      "name": "Payton Tang",
      "avatar_url": "https://avatars3.githubusercontent.com/u/19408042?v=4",
      "profile": "http://www.pcdeng.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Rem486",
      "name": "Rem486",
      "avatar_url": "https://avatars3.githubusercontent.com/u/22462424?v=4",
      "profile": "https://github.com/Rem486",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "BuptStEve",
      "name": "Steve Young",
      "avatar_url": "https://avatars2.githubusercontent.com/u/11501493?v=4",
      "profile": "https://buptsteve.github.io",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "olivewind",
      "name": "olive.wang",
      "avatar_url": "https://avatars0.githubusercontent.com/u/17901361?v=4",
      "profile": "http://olivewind.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "geekrainy",
      "name": "Rainy",
      "avatar_url": "https://avatars1.githubusercontent.com/u/7333266?v=4",
      "profile": "https://rainylog.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "daskyrk",
      "name": "随风",
      "avatar_url": "https://avatars2.githubusercontent.com/u/3955437?v=4",
      "profile": "https://github.com/daskyrk",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "JustClear",
      "name": "大板栗",
      "avatar_url": "https://avatars2.githubusercontent.com/u/7371867?v=4",
      "profile": "https://justclear.github.io/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "superman66",
      "name": "Superman",
      "avatar_url": "https://avatars0.githubusercontent.com/u/12592949?v=4",
      "profile": "https://github.com/superman66",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "PaytonDeng",
      "name": "Payton Deng",
      "avatar_url": "https://avatars2.githubusercontent.com/u/18691865?v=4",
      "profile": "https://github.com/PaytonDeng",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "hgrourou",
      "name": "Wang Kang",
      "avatar_url": "https://avatars1.githubusercontent.com/u/11886447?v=4",
      "profile": "https://github.com/hgrourou",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "w1301625107",
      "name": "wuchouchou",
      "avatar_url": "https://avatars2.githubusercontent.com/u/29950066?v=4",
      "profile": "https://github.com/w1301625107",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "EastblueOkay",
      "name": "EastblueOkay",
      "avatar_url": "https://avatars3.githubusercontent.com/u/13050584?v=4",
      "profile": "https://github.com/EastblueOkay",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "xybin1990",
      "name": "Nic",
      "avatar_url": "https://avatars2.githubusercontent.com/u/9530270?v=4",
      "profile": "https://github.com/xybin1990",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "CQBoyBrand",
      "name": "重庆崽儿Brand",
      "avatar_url": "https://avatars2.githubusercontent.com/u/20539402?v=4",
      "profile": "http://www.brandhuang.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "YanYuanFE",
      "name": "YanYuan",
      "avatar_url": "https://avatars2.githubusercontent.com/u/17774285?v=4",
      "profile": "http://yanyuanfe.cn",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "JunaYa",
      "name": "JunaYa",
      "avatar_url": "https://avatars0.githubusercontent.com/u/13215737?v=4",
      "profile": "http://junaya.github.io/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "licong96",
      "name": "黎聪",
      "avatar_url": "https://avatars1.githubusercontent.com/u/28621732?v=4",
      "profile": "https://github.com/licong96",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "a1055794033",
      "name": "WANGXUEFENG",
      "avatar_url": "https://avatars0.githubusercontent.com/u/33458200?v=4",
      "profile": "https://github.com/a1055794033",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "hansnow",
      "name": "Xiaohan Li",
      "avatar_url": "https://avatars2.githubusercontent.com/u/4365899?v=4",
      "profile": "https://hansnow.me",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "poyiding",
      "name": "dingkang",
      "avatar_url": "https://avatars3.githubusercontent.com/u/15643321?v=4",
      "profile": "https://yuque.com/zhifei",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "zhangciwu",
      "name": "zhangciwu",
      "avatar_url": "https://avatars2.githubusercontent.com/u/3340597?v=4",
      "profile": "http://zcw.me",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "sea-ice",
      "name": "Jack",
      "avatar_url": "https://avatars3.githubusercontent.com/u/25540882?v=4",
      "profile": "http://www.seaiceblog.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "masterZSH",
      "name": "masterZSH",
      "avatar_url": "https://avatars3.githubusercontent.com/u/27674875?v=4",
      "profile": "https://github.com/masterZSH",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Eve-1995",
      "name": "Eve",
      "avatar_url": "https://avatars1.githubusercontent.com/u/30228406?v=4",
      "profile": "http://angular.ink",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Xuemuyang",
      "name": "Xuemuyang",
      "avatar_url": "https://avatars0.githubusercontent.com/u/25718776?v=4",
      "profile": "http://myoungxue.top",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Jasery",
      "name": "Jasery",
      "avatar_url": "https://avatars2.githubusercontent.com/u/20091279?v=4",
      "profile": "https://github.com/Jasery",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "lmislm",
      "name": "Baskerville*",
      "avatar_url": "https://avatars1.githubusercontent.com/u/21683339?v=4",
      "profile": "https://lmislm.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "FishPlusOrange",
      "name": "FishPlusOrange",
      "avatar_url": "https://avatars0.githubusercontent.com/u/22132265?v=4",
      "profile": "https://github.com/FishPlusOrange",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "CodeDaraW",
      "name": "月迷津渡",
      "avatar_url": "https://avatars2.githubusercontent.com/u/12277082?v=4",
      "profile": "https://blog.daraw.cn/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "evinma",
      "name": "evinma",
      "avatar_url": "https://avatars2.githubusercontent.com/u/16096567?v=4",
      "profile": "https://github.com/evinma",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "suyanhanx",
      "name": "Suyan",
      "avatar_url": "https://avatars3.githubusercontent.com/u/24221472?v=4",
      "profile": "http://suyan.moe",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "luckymore",
      "name": "cherry-man",
      "avatar_url": "https://avatars0.githubusercontent.com/u/5390013?v=4",
      "profile": "https://github.com/luckymore",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Cainankun",
      "name": "蔡南坤",
      "avatar_url": "https://avatars3.githubusercontent.com/u/21698272?v=4",
      "profile": "https://github.com/Cainankun",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "cWatermelon",
      "name": "chenc",
      "avatar_url": "https://avatars0.githubusercontent.com/u/16097887?v=4",
      "profile": "https://github.com/cWatermelon",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "lxx2013",
      "name": "Xinxing Li",
      "avatar_url": "https://avatars3.githubusercontent.com/u/20529542?v=4",
      "profile": "https://setsuna.wang",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "BryanAdamss",
      "name": "GuangHui",
      "avatar_url": "https://avatars3.githubusercontent.com/u/7441504?v=4",
      "profile": "https://bryanadamss.github.io/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "CosSalt",
      "name": "odzcdut",
      "avatar_url": "https://avatars3.githubusercontent.com/u/36765589?v=4",
      "profile": "https://www.hosalt.cn/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "xhwgood",
      "name": "项鸿伟",
      "avatar_url": "https://avatars2.githubusercontent.com/u/39004078?v=4",
      "profile": "https://github.com/xhwgood",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "xie-zhichao",
      "name": "xiezhichao",
      "avatar_url": "https://avatars3.githubusercontent.com/u/15844643?v=4",
      "profile": "https://github.com/xie-zhichao",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "wqcstrong",
      "name": "Charles",
      "avatar_url": "https://avatars1.githubusercontent.com/u/23474513?v=4",
      "profile": "http://www.geeecko.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Jexxie",
      "name": "Jexxie",
      "avatar_url": "https://avatars1.githubusercontent.com/u/31770433?v=4",
      "profile": "https://twitter.com/Jexxie_woo",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "SeanWangx",
      "name": "Sean Wong",
      "avatar_url": "https://avatars3.githubusercontent.com/u/16217316?v=4",
      "profile": "https://github.com/SeanWangx",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "bluelovers",
      "name": "bluelovers",
      "avatar_url": "https://avatars0.githubusercontent.com/u/167966?v=4",
      "profile": "http://bluelovers.net",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "celery8911",
      "name": "Celery",
      "avatar_url": "https://avatars2.githubusercontent.com/u/24710064?v=4",
      "profile": "https://github.com/celery8911",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "chenxiaochun",
      "name": "chenxiaochun",
      "avatar_url": "https://avatars3.githubusercontent.com/u/1744713?v=4",
      "profile": "https://github.com/chenxiaochun",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "DuYueYu",
      "name": "Yates",
      "avatar_url": "https://avatars2.githubusercontent.com/u/41691152?v=4",
      "profile": "https://github.com/DuYueYu",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "IGoRFonin",
      "name": "IGoR",
      "avatar_url": "https://avatars2.githubusercontent.com/u/10962426?v=4",
      "profile": "https://github.com/IGoRFonin",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "byog",
      "name": "byog",
      "avatar_url": "https://avatars0.githubusercontent.com/u/7764115?v=4",
      "profile": "https://github.com/byog",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "whinc",
      "name": "whincwu",
      "avatar_url": "https://avatars2.githubusercontent.com/u/5096493?v=4",
      "profile": "https://github.com/whinc/blog",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "frontdog",
      "name": "康东扬",
      "avatar_url": "https://avatars2.githubusercontent.com/u/13433074?v=4",
      "profile": "https://github.com/frontdog",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Kennytian",
      "name": "Kenny",
      "avatar_url": "https://avatars3.githubusercontent.com/u/2621619?v=4",
      "profile": "https://www.jianshu.com/u/f4907e8670cb",
      "contributions": [
        "infra"
      ]
    },
    {
      "login": "cangSDARM",
      "name": "AllenLee",
      "avatar_url": "https://avatars0.githubusercontent.com/u/20441896?v=4",
      "profile": "https://www.douban.com/people/driving555/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "xiangming25",
      "name": "xiangming25",
      "avatar_url": "https://avatars3.githubusercontent.com/u/7913751?v=4",
      "profile": "https://github.com/xiangming25",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "vinzid",
      "name": "Chanvin Xiao",
      "avatar_url": "https://avatars1.githubusercontent.com/u/18076739?v=4",
      "profile": "https://chanvinxiao.com",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Aaron00101010",
      "name": "Aaron Xie",
      "avatar_url": "https://avatars0.githubusercontent.com/u/25996236?v=4",
      "profile": "http://www.noobcoder.club",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "nulIptr",
      "name": "nulIptr",
      "avatar_url": "https://avatars1.githubusercontent.com/u/7925831?v=4",
      "profile": "https://github.com/nulIptr",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "htoooth",
      "name": "Tao Huang",
      "avatar_url": "https://avatars3.githubusercontent.com/u/1717023?v=4",
      "profile": "http://www.cnblogs.com/htoooth/",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "Yunfly",
      "name": "Yunfly",
      "avatar_url": "https://avatars1.githubusercontent.com/u/19400116?v=4",
      "profile": "https://github.com/Yunfly",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "willww64",
      "name": "Will Wang",
      "avatar_url": "https://avatars2.githubusercontent.com/u/9930358?v=4",
      "profile": "https://github.com/willww64",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "SyMind",
      "name": "SyMind",
      "avatar_url": "https://avatars1.githubusercontent.com/u/19852293?v=4",
      "profile": "https://github.com/SyMind",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "yuhengshen",
      "name": "yuhengshen",
      "avatar_url": "https://avatars2.githubusercontent.com/u/29867660?v=4",
      "profile": "https://github.com/yuhengshen",
      "contributions": [
        "doc"
      ]
    },
    {
      "login": "ProfBramble",
      "name": "chenfeng",
      "avatar_url": "https://avatars0.githubusercontent.com/u/48615696?v=4",
      "profile": "https://github.com/ProfBramble",
      "contributions": [
        "doc"
      ]
    }
  ]
}


================================================
FILE: .gitattributes
================================================
*.js linguist-language=TypeScript

================================================
FILE: .github/workflows/gh-pages.yml
================================================
name: github pages

on:
  pull_request:
    types: [closed]
    branches:
      - master

  push:
    branches:
      - master

jobs:
  build-deploy:
    runs-on: ubuntu-18.04
    steps:
    - name: Checkout
      uses: actions/checkout@master
      with:
        ref: master

    - name: Install Dependencies
      run: yarn

    - name: Build
      run: yarn build

    - name: Deploy
      uses: peaceiris/actions-gh-pages@v2
      env:
        ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
        PUBLISH_BRANCH: gh-pages
        PUBLISH_DIR: ./docs/.vuepress/dist


================================================
FILE: .gitignore
================================================
.DS_Store
node_modules/
dist
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
.vs
*.suo
*.ntvs*
*.njsproj
*.sln

# Others
.history


================================================
FILE: .huskyrc.js
================================================
module.exports = {
  hooks: {
    'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS'
    // 'pre-commit': 'lint-staged'
  }
};


================================================
FILE: .prettierrc
================================================
{
  "printWidth": 120,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "none",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "arrowParens": "avoid",
  "requirePragma": false,
  "proseWrap": "preserve"
}

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 三毛

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# 深入理解 TypeScript

[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)](#contributors)
[![GitHub forks](https://img.shields.io/github/forks/jkchao/typescript-book-chinese.svg?style=flat-square)](https://github.com/jkchao/typescript-book-chinese/network) [![GitHub stars](https://img.shields.io/github/stars/jkchao/typescript-book-chinese.svg?style=flat-square)](https://github.com/jkchao/typescript-book-chinese/stargazers) [![GitHub issues](https://img.shields.io/github/issues/jkchao/typescript-book-chinese.svg?style=flat-square)](https://github.com/jkchao/typescript-book-chinese/issues)
[![GitHub last commit](https://img.shields.io/github/last-commit/jkchao/typescript-book-chinese.svg?style=flat-square)](https://github.com/jkchao/typescript-book-chinese/commits/master)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)

此书是 [《TypeScript Deep Dive》](https://github.com/basarat/typescript-book/) 的中文翻译版,感谢作者 [Basarat](https://github.com/basarat) 的付出。

如果你喜欢纸质书籍,可以通过[京东](https://item.jd.com/12755624.html)或者[当当](http://product.m.dangdang.com/28487648.html?t=1574581821),来购买此书。

你可以通过订阅该[公众号](https://cdn.jkchao.cn/nuxt/img/14958af.jpg),来获取更多有趣的内容。

## Why

![downloads](https://github.com/jkchao/typescript-book-chinese/raw/master/docs/.vuepress/public/typescript-downloads.jpg)

> 数据来源:[npm 包下载量](https://npm-stat.com/charts.html?package=typescript&from=2016-01-01&to=2018-07-31)

如你所见,TypeScript 发展至今,已经成为大型项目的标配,其提供的静态类型系统,大大增强了代码的可读性以及可维护性;同时,它提供最新和不断发展的 JavaScript 特性,能让我们建立更健壮的组件。

[《TypeScript Deep Dive》](https://github.com/basarat/typescript-book/) 是一本很好的开源书,从基础到深入,很全面的阐述了 TypeScript 的各种魔法,不管你是新手,还是老鸟,它都将适应你。此外,它不同于 TypeScript 官方给出的文档(当然 TypeScript 给出的文档是很好的),在此书中,结合实际应用下的场景用例,你将能更深入的理解 TypeScript。

如今社区已经存在部分翻译,但都似乎已经停止更新。

于是在某天的某个冲动之下,这个 RP 就诞生了。

## 翻译内容

《TypeScript Deep Dive》 书中包含一部分 JavaScript Future 和一些其他的内容,在这里,我们并不打算翻译它,如果你有兴趣,可以查看原书中 [JavaScript Future](https://basarat.gitbooks.io/typescript/content/docs/future-javascript.html) 的有关章节。

由于 TypeScript 更新频繁,除了上文中提到翻译部分,将会加入 TypeScript 的 Release,同时我也将总结出工作中一些有意思的点,希望和大家相互学习,一起进步。

此外,在不违背原作者本意前提下,为了更直观的表达,部分内容将采用意译,而非直译。

## Contributors

Thanks goes to these wonderful people
([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
| [<img src="https://avatars3.githubusercontent.com/u/22933931?v=4" width="64px;" alt="三毛"/><br /><sub><b>三毛</b></sub>](https://jkchao.cn)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=jkchao "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/22536347?v=4" width="64px;" alt="KnorienChang"/><br /><sub><b>KnorienChang</b></sub>](https://github.com/KnorienChang)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=KnorienChang "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/7829098?v=4" width="64px;" alt="阿卡琳"/><br /><sub><b>阿卡琳</b></sub>](https://github.com/magic-akari)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=magic-akari "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/2362335?v=4" width="64px;" alt="hopalay"/><br /><sub><b>hopalay</b></sub>](https://github.com/hopalay)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=hopalay "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/13592559?v=4" width="64px;" alt="Xing Liu"/><br /><sub><b>Xing Liu</b></sub>](http://singsing.io/blog)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=S1ngS1ng "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/23144765?v=4" width="64px;" alt="chenwangji"/><br /><sub><b>chenwangji</b></sub>](https://github.com/chenwangji)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=chenwangji "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/28107509?v=4" width="64px;" alt="老农爱盐碱地"/><br /><sub><b>老农爱盐碱地</b></sub>](https://github.com/helloforrestworld)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=helloforrestworld "Documentation") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [<img src="https://avatars2.githubusercontent.com/u/9589686?v=4" width="64px;" alt="Necros"/><br /><sub><b>Necros</b></sub>](http://www.itxuye.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=itxuye "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/8039013?v=4" width="64px;" alt="Xu Jihan"/><br /><sub><b>Xu Jihan</b></sub>](https://xutoto.im)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=XuToTo "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/7876498?v=4" width="64px;" alt="Yu"/><br /><sub><b>Yu</b></sub>](https://wanan.me/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Yiiu "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/11386122?v=4" width="64px;" alt="Yoga Lin"/><br /><sub><b>Yoga Lin</b></sub>](https://github.com/YogaLin)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=YogaLin "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/12699258?v=4" width="64px;" alt="G"/><br /><sub><b>G</b></sub>](http://galenjiang.github.io)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=galenjiang "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/37131109?v=4" width="64px;" alt="Undrum"/><br /><sub><b>Undrum</b></sub>](https://github.com/Undrum)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Undrum "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/22429236?v=4" width="64px;" alt="Zong"/><br /><sub><b>Zong</b></sub>](https://zongzi531.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=zongzi531 "Documentation") |
| [<img src="https://avatars0.githubusercontent.com/u/12185175?v=4" width="64px;" alt="LXVC"/><br /><sub><b>LXVC</b></sub>](http://lxvc.github.io)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=LXVC "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/20592013?v=4" width="64px;" alt="Whale"/><br /><sub><b>Whale</b></sub>](https://github.com/jinrichardJIN)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=jinrichardJIN "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/23274794?v=4" width="64px;" alt="getdaydream"/><br /><sub><b>getdaydream</b></sub>](https://github.com/getdaydream)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=getdaydream "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/9999765?v=4" width="64px;" alt="Ling ZiQing"/><br /><sub><b>Ling ZiQing</b></sub>](https://www.onlyling.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=onlyling "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/10740043?v=4" width="64px;" alt="izayl"/><br /><sub><b>izayl</b></sub>](https://github.com/izayl)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=izayl "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/21151080?v=4" width="64px;" alt="Moorez"/><br /><sub><b>Moorez</b></sub>](http://shenzekun.cn/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=shenzekun "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/26736658?v=4" width="64px;" alt="萤火之未"/><br /><sub><b>萤火之未</b></sub>](https://github.com/yepbug)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=yepbug "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/6301070?v=4" width="64px;" alt="xfields"/><br /><sub><b>xfields</b></sub>](https://github.com/xfields)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=xfields "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/16488686?v=4" width="64px;" alt="ZhaZheng"/><br /><sub><b>ZhaZheng</b></sub>](https://segmentfault.com/u/zhazhengrefn)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=ZhaZhengRefn "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/2196373?v=4" width="64px;" alt="弘树@阿里"/><br /><sub><b>弘树@阿里</b></sub>](http://webminer.js.org)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=dickeylth "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/1576121?v=4" width="64px;" alt="wangjingchao"/><br /><sub><b>wangjingchao</b></sub>](https://github.com/dalphyx)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=dalphyx "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/17974631?v=4" width="64px;" alt="IWANABETHATGUY"/><br /><sub><b>IWANABETHATGUY</b></sub>](https://github.com/IWANABETHATGUY)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=IWANABETHATGUY "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/19408042?v=4" width="64px;" alt="Payton Tang"/><br /><sub><b>Payton Tang</b></sub>](http://www.pcdeng.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=PaytonTang "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/22462424?v=4" width="64px;" alt="Rem486"/><br /><sub><b>Rem486</b></sub>](https://github.com/Rem486)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Rem486 "Documentation") |
| [<img src="https://avatars2.githubusercontent.com/u/11501493?v=4" width="64px;" alt="Steve Young"/><br /><sub><b>Steve Young</b></sub>](https://buptsteve.github.io)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=BuptStEve "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/17901361?v=4" width="64px;" alt="olive.wang"/><br /><sub><b>olive.wang</b></sub>](http://olivewind.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=olivewind "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/7333266?v=4" width="64px;" alt="Rainy"/><br /><sub><b>Rainy</b></sub>](https://rainylog.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=geekrainy "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/3955437?v=4" width="64px;" alt="随风"/><br /><sub><b>随风</b></sub>](https://github.com/daskyrk)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=daskyrk "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/7371867?v=4" width="64px;" alt="大板栗"/><br /><sub><b>大板栗</b></sub>](https://justclear.github.io/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=JustClear "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/12592949?v=4" width="64px;" alt="Superman"/><br /><sub><b>Superman</b></sub>](https://github.com/superman66)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=superman66 "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/18691865?v=4" width="64px;" alt="Payton Deng"/><br /><sub><b>Payton Deng</b></sub>](https://github.com/PaytonDeng)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=PaytonDeng "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/11886447?v=4" width="64px;" alt="Wang Kang"/><br /><sub><b>Wang Kang</b></sub>](https://github.com/hgrourou)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=hgrourou "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/29950066?v=4" width="64px;" alt="wuchouchou"/><br /><sub><b>wuchouchou</b></sub>](https://github.com/w1301625107)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=w1301625107 "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/13050584?v=4" width="64px;" alt="EastblueOkay"/><br /><sub><b>EastblueOkay</b></sub>](https://github.com/EastblueOkay)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=EastblueOkay "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/9530270?v=4" width="64px;" alt="Nic"/><br /><sub><b>Nic</b></sub>](https://github.com/xybin1990)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=xybin1990 "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/20539402?v=4" width="64px;" alt="重庆崽儿Brand"/><br /><sub><b>重庆崽儿Brand</b></sub>](http://www.brandhuang.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=CQBoyBrand "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/17774285?v=4" width="64px;" alt="YanYuan"/><br /><sub><b>YanYuan</b></sub>](http://yanyuanfe.cn)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=YanYuanFE "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/13215737?v=4" width="64px;" alt="JunaYa"/><br /><sub><b>JunaYa</b></sub>](http://junaya.github.io/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=JunaYa "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/28621732?v=4" width="64px;" alt="黎聪"/><br /><sub><b>黎聪</b></sub>](https://github.com/licong96)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=licong96 "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/33458200?v=4" width="64px;" alt="WANGXUEFENG"/><br /><sub><b>WANGXUEFENG</b></sub>](https://github.com/a1055794033)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=a1055794033 "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/4365899?v=4" width="64px;" alt="Xiaohan Li"/><br /><sub><b>Xiaohan Li</b></sub>](https://hansnow.me)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=hansnow "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/15643321?v=4" width="64px;" alt="dingkang"/><br /><sub><b>dingkang</b></sub>](https://yuque.com/zhifei)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=poyiding "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/3340597?v=4" width="64px;" alt="zhangciwu"/><br /><sub><b>zhangciwu</b></sub>](http://zcw.me)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=zhangciwu "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/25540882?v=4" width="64px;" alt="Jack"/><br /><sub><b>Jack</b></sub>](http://www.seaiceblog.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=sea-ice "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/27674875?v=4" width="64px;" alt="masterZSH"/><br /><sub><b>masterZSH</b></sub>](https://github.com/masterZSH)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=masterZSH "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/30228406?v=4" width="64px;" alt="Eve"/><br /><sub><b>Eve</b></sub>](http://angular.ink)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Eve-1995 "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/25718776?v=4" width="64px;" alt="Xuemuyang"/><br /><sub><b>Xuemuyang</b></sub>](http://myoungxue.top)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Xuemuyang "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/20091279?v=4" width="64px;" alt="Jasery"/><br /><sub><b>Jasery</b></sub>](https://github.com/Jasery)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Jasery "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/21683339?v=4" width="64px;" alt="Baskerville*"/><br /><sub><b>Baskerville*</b></sub>](https://lmislm.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=lmislm "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/22132265?v=4" width="64px;" alt="FishPlusOrange"/><br /><sub><b>FishPlusOrange</b></sub>](https://github.com/FishPlusOrange)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=FishPlusOrange "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/12277082?v=4" width="64px;" alt="月迷津渡"/><br /><sub><b>月迷津渡</b></sub>](https://blog.daraw.cn/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=CodeDaraW "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/16096567?v=4" width="64px;" alt="evinma"/><br /><sub><b>evinma</b></sub>](https://github.com/evinma)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=evinma "Documentation") |
| [<img src="https://avatars3.githubusercontent.com/u/24221472?v=4" width="64px;" alt="Suyan"/><br /><sub><b>Suyan</b></sub>](http://suyan.moe)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=suyanhanx "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/5390013?v=4" width="64px;" alt="cherry-man"/><br /><sub><b>cherry-man</b></sub>](https://github.com/luckymore)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=luckymore "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/21698272?v=4" width="64px;" alt="蔡南坤"/><br /><sub><b>蔡南坤</b></sub>](https://github.com/Cainankun)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Cainankun "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/16097887?v=4" width="64px;" alt="chenc"/><br /><sub><b>chenc</b></sub>](https://github.com/cWatermelon)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=cWatermelon "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/20529542?v=4" width="64px;" alt="Xinxing Li"/><br /><sub><b>Xinxing Li</b></sub>](https://setsuna.wang)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=lxx2013 "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/7441504?v=4" width="64px;" alt="GuangHui"/><br /><sub><b>GuangHui</b></sub>](https://bryanadamss.github.io/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=BryanAdamss "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/36765589?v=4" width="64px;" alt="odzcdut"/><br /><sub><b>odzcdut</b></sub>](https://www.hosalt.cn/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=CosSalt "Documentation") |
| [<img src="https://avatars2.githubusercontent.com/u/39004078?v=4" width="64px;" alt="项鸿伟"/><br /><sub><b>项鸿伟</b></sub>](https://github.com/xhwgood)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=xhwgood "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/15844643?v=4" width="64px;" alt="xiezhichao"/><br /><sub><b>xiezhichao</b></sub>](https://github.com/xie-zhichao)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=xie-zhichao "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/23474513?v=4" width="64px;" alt="Charles"/><br /><sub><b>Charles</b></sub>](http://www.geeecko.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=wqcstrong "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/31770433?v=4" width="64px;" alt="Jexxie"/><br /><sub><b>Jexxie</b></sub>](https://twitter.com/Jexxie_woo)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Jexxie "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/16217316?v=4" width="64px;" alt="Sean Wong"/><br /><sub><b>Sean Wong</b></sub>](https://github.com/SeanWangx)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=SeanWangx "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/167966?v=4" width="64px;" alt="bluelovers"/><br /><sub><b>bluelovers</b></sub>](http://bluelovers.net)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=bluelovers "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/24710064?v=4" width="64px;" alt="Celery"/><br /><sub><b>Celery</b></sub>](https://github.com/celery8911)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=celery8911 "Documentation") |
| [<img src="https://avatars3.githubusercontent.com/u/1744713?v=4" width="64px;" alt="chenxiaochun"/><br /><sub><b>chenxiaochun</b></sub>](https://github.com/chenxiaochun)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=chenxiaochun "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/41691152?v=4" width="64px;" alt="Yates"/><br /><sub><b>Yates</b></sub>](https://github.com/DuYueYu)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=DuYueYu "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/10962426?v=4" width="64px;" alt="IGoR"/><br /><sub><b>IGoR</b></sub>](https://github.com/IGoRFonin)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=IGoRFonin "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/7764115?v=4" width="64px;" alt="byog"/><br /><sub><b>byog</b></sub>](https://github.com/byog)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=byog "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/5096493?v=4" width="64px;" alt="whincwu"/><br /><sub><b>whincwu</b></sub>](https://github.com/whinc/blog)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=whinc "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/13433074?v=4" width="64px;" alt="康东扬"/><br /><sub><b>康东扬</b></sub>](https://github.com/frontdog)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=frontdog "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/2621619?v=4" width="64px;" alt="Kenny"/><br /><sub><b>Kenny</b></sub>](https://www.jianshu.com/u/f4907e8670cb)<br />[🚇](#infra-Kennytian "Infrastructure (Hosting, Build-Tools, etc)") |
| [<img src="https://avatars0.githubusercontent.com/u/20441896?v=4" width="64px;" alt="AllenLee"/><br /><sub><b>AllenLee</b></sub>](https://www.douban.com/people/driving555/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=cangSDARM "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/7913751?v=4" width="64px;" alt="xiangming25"/><br /><sub><b>xiangming25</b></sub>](https://github.com/xiangming25)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=xiangming25 "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/18076739?v=4" width="64px;" alt="Chanvin Xiao"/><br /><sub><b>Chanvin Xiao</b></sub>](https://chanvinxiao.com)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=vinzid "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/25996236?v=4" width="64px;" alt="Aaron Xie"/><br /><sub><b>Aaron Xie</b></sub>](http://www.noobcoder.club)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Aaron00101010 "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/7925831?v=4" width="64px;" alt="nulIptr"/><br /><sub><b>nulIptr</b></sub>](https://github.com/nulIptr)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=nulIptr "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/1717023?v=4" width="64px;" alt="Tao Huang"/><br /><sub><b>Tao Huang</b></sub>](http://www.cnblogs.com/htoooth/)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=htoooth "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/19400116?v=4" width="64px;" alt="Yunfly"/><br /><sub><b>Yunfly</b></sub>](https://github.com/Yunfly)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=Yunfly "Documentation") |
| [<img src="https://avatars2.githubusercontent.com/u/9930358?v=4" width="64px;" alt="Will Wang"/><br /><sub><b>Will Wang</b></sub>](https://github.com/willww64)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=willww64 "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/19852293?v=4" width="64px;" alt="SyMind"/><br /><sub><b>SyMind</b></sub>](https://github.com/SyMind)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=SyMind "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/29867660?v=4" width="64px;" alt="yuhengshen"/><br /><sub><b>yuhengshen</b></sub>](https://github.com/yuhengshen)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=yuhengshen "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/48615696?v=4" width="64px;" alt="chenfeng"/><br /><sub><b>chenfeng</b></sub>](https://github.com/ProfBramble)<br />[📖](https://github.com/jkchao/typescript-book-chinese/commits?author=ProfBramble "Documentation") |

<!-- ALL-CONTRIBUTORS-LIST:END -->

## How to contribute

你可以:

- 通过 PR 修改错别字,或者错误的格式;
- 发 issue 讨论文章中出现的一些不合理地方;
- 翻译 TODO 文件夹下的文章,并顺手 Email 我。

希望你在翻译或者 PR 之前,阅读[中文文章排版指北](https://github.com/mzlogin/chinese-copywriting-guidelines)。

### 公众号

<img src="./docs/.vuepress/public/qrcode.jpg" width="200" />

## 最后

如果你和我一样对 TypeScript 充满兴趣,可以订阅(star)本项目,及时收到有关于此项目的更新。

如果你对文章有任何疑问,欢迎提交 [issues](https://github.com/jkchao/typescript-book-chinese/issues) 和我交流。

如果你认为有些地方翻译不够准确,或者你想补充一些文中没提到但是非常有意思的知识点,欢迎 [PR](https://github.com/jkchao/typescript-book-chinese/pulls)。


================================================
FILE: commitlint.config.js
================================================
const types = ['build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test', 'chore', 'update'];

module.exports = {
  // https://github.com/conventional-changelog/commitlint/blob/master/%40commitlint/config-angular/README.md
  extends: ['@commitlint/config-angular'],

  rules: {
    'type-enum': [2, 'always', types]
  }
};


================================================
FILE: docs/.vuepress/config.js
================================================
module.exports = {
  base: '/typescript-book-chinese/',
  title: '深入理解 TypeScript',
  description: 'TypeScript Deep Dive 中文版',
  head: [
    ['link', { rel: 'icon', href: `/logo.png` }],
    ['link', { rel: 'manifest', href: '/manifest.json' }],
    ['meta', { name: 'theme-color', content: '#3eaf7c' }],
    ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
    ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }],
    ['meta', { name: 'msapplication-TileColor', content: '#000000' }]
  ],
  plugins: [
    // '@vuepress/pwa',
    '@vuepress/back-to-top',
    [
      '@vuepress/google-analytics',
      {
        ga: 'UA-106861408-1' // UA-00000000-0
      }
    ]
  ],
  // theme: [],
  themeConfig: {
    repo: 'jkchao/typescript-book-chinese',
    docsDir: 'docs',
    editLinks: true,
    editLinkText: '编辑此页',
    activeHeaderLinks: false,
    sidebarDepth: 3,
    lastUpdated: '上次更新',
    // algolia: {
    //   apiKey: 'fd0efd57c48824ceb1bcfa9690dba5b0',
    //   indexName: 'jkchao_typescript'
    // },
    adsConfig: [
      { title: '关注公众号', src: '/typescript-book-chinese/qrcode.jpg' },
      { title: '与我交流', src: '/typescript-book-chinese/contact.png' },
      {
        title: '购买此书',
        src:
          'https://static.jkchao.cn/2019-11-22/WechatIMG719.png?imageMogr2/auto-orient/thumbnail/80x/blur/1x0/quality/75|imageslim',
        url: 'https://item.jd.com/12755624.html'
      }
    ],
    nav: [
      { text: '原书链接', link: 'https://basarat.gitbooks.io/typescript/content/docs/getting-started.html' },
      { text: 'Blog', link: 'https://jkchao.cn' }
    ],
    sidebar: [
      {
        title: '写在前面',
        collapsable: false,
        children: ['/']
      },
      {
        title: 'TypeScript 项目',
        collapsable: false,
        children: [
          '/project/compilationContext',
          '/project/declarationspaces',
          '/project/modules',
          '/project/namespaces',
          '/project/dynamicImportExpressions'
        ]
      },
      {
        title: 'TypeScript 类型系统',
        collapsable: false,
        children: [
          '/typings/overview',
          '/typings/migrating',
          '/typings/types',
          '/typings/ambient',
          '/typings/interfaces',
          '/typings/enums',
          '/typings/lib',
          '/typings/functions',
          '/typings/callable',
          '/typings/typeAssertion',
          '/typings/freshness',
          '/typings/typeGuard',
          '/typings/literals',
          '/typings/readonly',
          '/typings/generices',
          '/typings/typeInference',
          '/typings/typeCompatibility',
          '/typings/neverType',
          '/typings/discrominatedUnion',
          '/typings/indexSignatures',
          '/typings/movingTypes',
          '/typings/exceptionsHanding',
          '/typings/mixins',
          '/typings/thisType'
        ]
      },
      {
        title: 'JSX',
        collapsable: false,
        children: ['/jsx/support', '/jsx/reactJSX', '/jsx/nonReactJSX']
      },
      {
        title: 'TypeScript 错误提示',
        collapsable: false,
        children: ['/error/interpreting', '/error/common']
      },
      {
        title: 'TIPs',
        collapsable: false,
        children: [
          '/tips/stringBasedEmuns',
          '/tips/nominalTyping',
          '/tips/statefulFunctions',
          '/tips/bind',
          '/tips/curry',
          '/tips/typeInstantiation',
          '/tips/lazyObjectLiteralInitialization',
          '/tips/classAreUseful',
          '/tips/avoidExportDefault',
          '/tips/limitPropertySetters',
          '/tips/createArrays',
          '/tips/outFileCaution',
          '/tips/staticConstructors',
          '/tips/singletonPatern',
          '/tips/functionParameters',
          '/tips/truthy',
          '/tips/buildToggles',
          '/tips/typesafeEventEmitter',
          '/tips/metadata',
          '/tips/covarianceAndContravariance',
          '/tips/infer'
        ]
      },
      {
        title: 'TypeScript 编译原理',
        collapsable: false,
        children: [
          '/compiler/overview',
          '/compiler/program',
          '/compiler/ast',
          '/compiler/scanner',
          '/compiler/parser',
          '/compiler/binder',
          '/compiler/checker',
          '/compiler/emitter'
        ]
      },
      {
        title: 'TypeScript FAQs',
        collapsable: false,
        children: [
          './faqs/common-bug-not-bugs',
          './faqs/common-feature-request',
          './faqs/type-system-behavior',
          './faqs/function',
          './faqs/class',
          './faqs/generics',
          './faqs/modules',
          './faqs/enums',
          './faqs/type-guards',
          './faqs/jsx-and-react',
          './faqs/thing-that-dont-work',
          './faqs/commandline-behavior',
          './faqs/tsconfig-behavior'
        ]
      },
      {
        title: 'TypeScript 更新',
        collapsable: false,
        children: ['/new/typescript-3.9', '/new/typescript-3.8', '/new/typescript-3.7']
      }
      // {
      //   title: 'TypeScript 更新',
      //   collapsable: false,
      //   children: ['/new/typescript-3.7']
      // }
    ]
  }
};


================================================
FILE: docs/.vuepress/public/manifest.json
================================================
{
  "name": "TypeScriptBook",
  "short_name": "TypeScriptBook",
  "icons": [
    {
      "src": "/icons/android-chrome-36x36.png",
      "sizes": "36x36",
      "type": "image/png",
      "density": 0.75
    },
    {
      "src": "/icons/android-chrome-48x48.png",
      "sizes": "48x48",
      "type": "image/png",
      "density": 1
    },
    {
      "src": "/icons/android-chrome-72x72.png",
      "sizes": "72x72",
      "type": "image/png",
      "density": 1.5
    },
    {
      "src": "/icons/android-chrome-96x96.png",
      "sizes": "96x96",
      "type": "image/png",
      "density": 2
    },
    {
      "src": "/icons/android-chrome-144x144.png",
      "sizes": "144x144",
      "type": "image/png",
      "density": 3
    },
    {
      "src": "/icons/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "density": 4
    }
  ],
  "start_url": "/typescript-book-chinese/",
  "display": "standalone",
  "background_color": "#fff",
  "theme_color": "#3eaf7c"
}


================================================
FILE: docs/.vuepress/theme/components/Ads.vue
================================================
<template>
  <div class="ads">
    <div
      class="item"
      v-for="ads in $themeConfig.adsConfig">
      <h6 class="title" v-show="!notName">{{ads.title}}</h6>
      <div class="thumb">
        <a  :href="ads.url || ads.src" target="_blank">
          <img :src="ads.src" :alt="ads.title">
        </a>

      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ads',
  props: ['notName']
}
</script>

<style scoped lang="stylus">
.ads 
  position fixed;
  z-index 99;
  top 90px;
  right 20px;
  width 100px;


@media (max-width: 1270px)
  .ads 
    display none;

.item 
  text-align center;


img 
  max-width 80px;


h6 
  margin .4rem;

</style>


================================================
FILE: docs/.vuepress/theme/components/AlgoliaSearchBox.vue
================================================
<template>
  <form
    id="search-form"
    class="algolia-search-wrapper search-box"
    role="search"
  >
    <input
      id="algolia-search-input"
      class="search-query"
    >
  </form>
</template>

<script>
export default {
  props: ['options'],

  mounted () {
    this.initialize(this.options, this.$lang)
  },

  methods: {
    initialize (userOptions, lang) {
      Promise.all([
        import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.js'),
        import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.css')
      ]).then(([docsearch]) => {
        docsearch = docsearch.default
        const { algoliaOptions = {}} = userOptions
        docsearch(Object.assign(
          {},
          userOptions,
          {
            inputSelector: '#algolia-search-input',
            // #697 Make docsearch work well at i18n mode.
            algoliaOptions: Object.assign({
              'facetFilters': [`lang:${lang}`].concat(algoliaOptions.facetFilters || [])
            }, algoliaOptions)
          }
        ))
      })
    },

    update (options, lang) {
      this.$el.innerHTML = '<input id="algolia-search-input" class="search-query">'
      this.initialize(options, lang)
    }
  },

  watch: {
    $lang (newValue) {
      this.update(this.options, newValue)
    },

    options (newValue) {
      this.update(newValue, this.$lang)
    }
  }
}
</script>

<style lang="stylus">
.algolia-search-wrapper
  & > span
    vertical-align middle
  .algolia-autocomplete
    line-height normal
    .ds-dropdown-menu
      background-color #fff
      border 1px solid #999
      border-radius 4px
      font-size 16px
      margin 6px 0 0
      padding 4px
      text-align left
      &:before
        border-color #999
      [class*=ds-dataset-]
        border none
        padding 0
      .ds-suggestions
        margin-top 0
      .ds-suggestion
        border-bottom 1px solid $borderColor
    .algolia-docsearch-suggestion--highlight
      color #2c815b
    .algolia-docsearch-suggestion
      border-color $borderColor
      padding 0
      .algolia-docsearch-suggestion--category-header
        padding 5px 10px
        margin-top 0
        background $accentColor
        color #fff
        font-weight 600
        .algolia-docsearch-suggestion--highlight
          background rgba(255, 255, 255, 0.6)
      .algolia-docsearch-suggestion--wrapper
        padding 0
      .algolia-docsearch-suggestion--title
        font-weight 600
        margin-bottom 0
        color $textColor
      .algolia-docsearch-suggestion--subcategory-column
        vertical-align top
        padding 5px 7px 5px 5px
        border-color $borderColor
        background #f1f3f5
        &:after
          display none
      .algolia-docsearch-suggestion--subcategory-column-text
        color #555
    .algolia-docsearch-footer
      border-color $borderColor
    .ds-cursor .algolia-docsearch-suggestion--content
      background-color #e7edf3 !important
      color $textColor

@media (min-width: $MQMobile)
  .algolia-search-wrapper
    .algolia-autocomplete
      .algolia-docsearch-suggestion
        .algolia-docsearch-suggestion--subcategory-column
          float none
          width 150px
          min-width 150px
          display table-cell
        .algolia-docsearch-suggestion--content
          float none
          display table-cell
          width 100%
          vertical-align top
        .ds-dropdown-menu
          min-width 515px !important

@media (max-width: $MQMobile)
  .algolia-search-wrapper
    .ds-dropdown-menu
      min-width calc(100vw - 4rem) !important
      max-width calc(100vw - 4rem) !important
    .algolia-docsearch-suggestion--wrapper
      padding 5px 7px 5px 5px !important
    .algolia-docsearch-suggestion--subcategory-column
      padding 0 !important
      background white !important
    .algolia-docsearch-suggestion--subcategory-column-text:after
      content " > "
      font-size 10px
      line-height 14.4px
      display inline-block
      width 5px
      margin -3px 3px 0
      vertical-align middle

</style>


================================================
FILE: docs/.vuepress/theme/components/DropdownLink.vue
================================================
<template>
  <div
    class="dropdown-wrapper"
    :class="{ open }"
  >
    <a
      class="dropdown-title"
      @click="toggle"
    >
      <span class="title">{{ item.text }}</span>
      <span
        class="arrow"
        :class="open ? 'down' : 'right'"
      ></span>
    </a>

    <DropdownTransition>
      <ul
        class="nav-dropdown"
        v-show="open"
      >
        <li
          class="dropdown-item"
          :key="subItem.link || index"
          v-for="(subItem, index) in item.items"
        >
          <h4 v-if="subItem.type === 'links'">{{ subItem.text }}</h4>

          <ul
            class="dropdown-subitem-wrapper"
            v-if="subItem.type === 'links'"
          >
            <li
              class="dropdown-subitem"
              :key="childSubItem.link"
              v-for="childSubItem in subItem.items"
            >
              <NavLink :item="childSubItem"/>
            </li>
          </ul>

          <NavLink
            v-else
            :item="subItem"
          />
        </li>
      </ul>
    </DropdownTransition>
  </div>
</template>

<script>
import NavLink from './NavLink.vue'
import DropdownTransition from './DropdownTransition.vue'

export default {
  components: { NavLink, DropdownTransition },

  data () {
    return {
      open: false
    }
  },

  props: {
    item: {
      required: true
    }
  },

  methods: {
    toggle () {
      this.open = !this.open
    }
  }
}
</script>

<style lang="stylus">
.dropdown-wrapper
  cursor pointer
  .dropdown-title
    display block
    &:hover
      border-color transparent
    .arrow
      vertical-align middle
      margin-top -1px
      margin-left 0.4rem
  .nav-dropdown
    .dropdown-item
      color inherit
      line-height 1.7rem
      h4
        margin 0.45rem 0 0
        border-top 1px solid #eee
        padding 0.45rem 1.5rem 0 1.25rem
      .dropdown-subitem-wrapper
        padding 0
        list-style none
        .dropdown-subitem
          font-size 0.9em
      a
        display block
        line-height 1.7rem
        position relative
        border-bottom none
        font-weight 400
        margin-bottom 0
        padding 0 1.5rem 0 1.25rem
        &:hover
          color $accentColor
        &.router-link-active
          color $accentColor
          &::after
            content ""
            width 0
            height 0
            border-left 5px solid $accentColor
            border-top 3px solid transparent
            border-bottom 3px solid transparent
            position absolute
            top calc(50% - 2px)
            left 9px
      &:first-child h4
        margin-top 0
        padding-top 0
        border-top 0

@media (max-width: $MQMobile)
  .dropdown-wrapper
    &.open .dropdown-title
      margin-bottom 0.5rem
    .nav-dropdown
      transition height .1s ease-out
      overflow hidden
      .dropdown-item
        h4
          border-top 0
          margin-top 0
          padding-top 0
        h4, & > a
          font-size 15px
          line-height 2rem
        .dropdown-subitem
          font-size 14px
          padding-left 1rem

@media (min-width: $MQMobile)
  .dropdown-wrapper
    height 1.8rem
    &:hover .nav-dropdown
      // override the inline style.
      display block !important
    .dropdown-title .arrow
      // make the arrow always down at desktop
      border-left 4px solid transparent
      border-right 4px solid transparent
      border-top 6px solid $arrowBgColor
      border-bottom 0
    .nav-dropdown
      display none
      // Avoid height shaked by clicking
      height auto !important
      box-sizing border-box;
      max-height calc(100vh - 2.7rem)
      overflow-y auto
      position absolute
      top 100%
      right 0
      background-color #fff
      padding 0.6rem 0
      border 1px solid #ddd
      border-bottom-color #ccc
      text-align left
      border-radius 0.25rem
      white-space nowrap
      margin 0
</style>


================================================
FILE: docs/.vuepress/theme/components/DropdownTransition.vue
================================================
<template>
  <transition
    name="dropdown"
    @enter="setHeight"
    @after-enter="unsetHeight"
    @before-leave="setHeight"
  >
    <slot/>
  </transition>
</template>

<script>
export default {
  name: 'DropdownTransition',

  methods: {
    setHeight (items) {
      // explicitly set height so that it can be transitioned
      items.style.height = items.scrollHeight + 'px'
    },

    unsetHeight (items) {
      items.style.height = ''
    }
  }
}
</script>

<style lang="stylus">
.dropdown-enter, .dropdown-leave-to
  height 0 !important

</style>


================================================
FILE: docs/.vuepress/theme/components/Home.vue
================================================
<template>
  <main class="home" aria-labelledby="main-title">
    <header class="hero">
      <img
        v-if="data.heroImage"
        :src="$withBase(data.heroImage)"
        alt="hero"
      >

      <h1 id="main-title">{{ data.heroText || $title || 'Hello' }}</h1>

      <p class="description">
        {{ data.tagline || $description || 'Welcome to your VuePress site' }}
      </p>

      <p
        class="action"
        v-if="data.actionText && data.actionLink"
      >
        <NavLink
          class="action-button"
          :item="actionLink"
        />
      </p>
    </header>

    <div
      class="features"
      v-if="data.features && data.features.length"
    >
      <div
        class="feature"
        v-for="(feature, index) in data.features"
        :key="index"
      >
        <h2>{{ feature.title }}</h2>
        <p>{{ feature.details }}</p>
      </div>
    </div>

    <Content class="custom"/>

    <div
      class="footer"
      v-if="data.footer"
    >
      {{ data.footer }}
    </div>
  </main>
</template>

<script>
import NavLink from './NavLink.vue'

export default {
  components: { NavLink },

  computed: {
    data () {
      return this.$page.frontmatter
    },

    actionLink () {
      return {
        link: this.data.actionLink,
        text: this.data.actionText
      }
    }
  }
}
</script>

<style lang="stylus">
.home
  padding $navbarHeight 2rem 0
  max-width 960px
  margin 0px auto
  display block
  .hero
    text-align center
    img
      max-width: 100%
      max-height 280px
      display block
      margin 3rem auto 1.5rem
    h1
      font-size 3rem
    h1, .description, .action
      margin 1.8rem auto
    .description
      max-width 35rem
      font-size 1.6rem
      line-height 1.3
      color lighten($textColor, 40%)
    .action-button
      display inline-block
      font-size 1.2rem
      color #fff
      background-color $accentColor
      padding 0.8rem 1.6rem
      border-radius 4px
      transition background-color .1s ease
      box-sizing border-box
      border-bottom 1px solid darken($accentColor, 10%)
      &:hover
        background-color lighten($accentColor, 10%)
  .features
    border-top 1px solid $borderColor
    padding 1.2rem 0
    margin-top 2.5rem
    display flex
    flex-wrap wrap
    align-items flex-start
    align-content stretch
    justify-content space-between
  .feature
    flex-grow 1
    flex-basis 30%
    max-width 30%
    h2
      font-size 1.4rem
      font-weight 500
      border-bottom none
      padding-bottom 0
      color lighten($textColor, 10%)
    p
      color lighten($textColor, 25%)
  .footer
    padding 2.5rem
    border-top 1px solid $borderColor
    text-align center
    color lighten($textColor, 25%)

@media (max-width: $MQMobile)
  .home
    .features
      flex-direction column
    .feature
      max-width 100%
      padding 0 2.5rem

@media (max-width: $MQMobileNarrow)
  .home
    padding-left 1.5rem
    padding-right 1.5rem
    .hero
      img
        max-height 210px
        margin 2rem auto 1.2rem
      h1
        font-size 2rem
      h1, .description, .action
        margin 1.2rem auto
      .description
        font-size 1.2rem
      .action-button
        font-size 1rem
        padding 0.6rem 1.2rem
    .feature
      h2
        font-size 1.25rem
</style>


================================================
FILE: docs/.vuepress/theme/components/NavLink.vue
================================================
<template>
  <router-link
    class="nav-link"
    :to="link"
    v-if="!isExternal(link)"
    :exact="exact"
  >{{ item.text }}</router-link>
  <a
    v-else
    :href="link"
    class="nav-link external"
    :target="isMailto(link) || isTel(link) ? null : '_blank'"
    :rel="isMailto(link) || isTel(link) ? null : 'noopener noreferrer'"
  >
    {{ item.text }}
    <OutboundLink/>
  </a>
</template>

<script>
import { isExternal, isMailto, isTel, ensureExt } from '../util'

export default {
  props: {
    item: {
      required: true
    }
  },

  computed: {
    link () {
      return ensureExt(this.item.link)
    },

    exact () {
      if (this.$site.locales) {
        return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link)
      }
      return this.link === '/'
    }
  },

  methods: {
    isExternal,
    isMailto,
    isTel
  }
}
</script>


================================================
FILE: docs/.vuepress/theme/components/NavLinks.vue
================================================
<template>
  <nav
    class="nav-links"
    v-if="userLinks.length || repoLink"
  >
    <!-- user links -->
    <div
      class="nav-item"
      v-for="item in userLinks"
      :key="item.link"
    >
      <DropdownLink
        v-if="item.type === 'links'"
        :item="item"
      />
      <NavLink
        v-else
        :item="item"
      />
    </div>

    <!-- repo link -->
    <a
      v-if="repoLink"
      :href="repoLink"
      class="repo-link"
      target="_blank"
      rel="noopener noreferrer"
    >
      {{ repoLabel }}
      <OutboundLink/>
    </a>
  </nav>
</template>

<script>
import DropdownLink from './DropdownLink.vue'
import { resolveNavLinkItem } from '../util'
import NavLink from './NavLink.vue'

export default {
  components: { NavLink, DropdownLink },

  computed: {
    userNav () {
      return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || []
    },

    nav () {
      const { locales } = this.$site
      if (locales && Object.keys(locales).length > 1) {
        const currentLink = this.$page.path
        const routes = this.$router.options.routes
        const themeLocales = this.$site.themeConfig.locales || {}
        const languageDropdown = {
          text: this.$themeLocaleConfig.selectText || 'Languages',
          items: Object.keys(locales).map(path => {
            const locale = locales[path]
            const text = themeLocales[path] && themeLocales[path].label || locale.lang
            let link
            // Stay on the current page
            if (locale.lang === this.$lang) {
              link = currentLink
            } else {
              // Try to stay on the same page
              link = currentLink.replace(this.$localeConfig.path, path)
              // fallback to homepage
              if (!routes.some(route => route.path === link)) {
                link = path
              }
            }
            return { text, link }
          })
        }
        return [...this.userNav, languageDropdown]
      }
      return this.userNav
    },

    userLinks () {
      return (this.nav || []).map(link => {
        return Object.assign(resolveNavLinkItem(link), {
          items: (link.items || []).map(resolveNavLinkItem)
        })
      })
    },

    repoLink () {
      const { repo } = this.$site.themeConfig
      if (repo) {
        return /^https?:/.test(repo)
          ? repo
          : `https://github.com/${repo}`
      }
    },

    repoLabel () {
      if (!this.repoLink) return
      if (this.$site.themeConfig.repoLabel) {
        return this.$site.themeConfig.repoLabel
      }

      const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0]
      const platforms = ['GitHub', 'GitLab', 'Bitbucket']
      for (let i = 0; i < platforms.length; i++) {
        const platform = platforms[i]
        if (new RegExp(platform, 'i').test(repoHost)) {
          return platform
        }
      }

      return 'Source'
    }
  }
}
</script>

<style lang="stylus">
.nav-links
  display inline-block
  a
    line-height 1.4rem
    color inherit
    &:hover, &.router-link-active
      color $accentColor
  .nav-item
    position relative
    display inline-block
    margin-left 1.5rem
    line-height 2rem
    &:first-child
      margin-left 0
  .repo-link
    margin-left 1.5rem

@media (max-width: $MQMobile)
  .nav-links
    .nav-item, .repo-link
      margin-left 0

@media (min-width: $MQMobile)
  .nav-links a
    &:hover, &.router-link-active
      color $textColor
  .nav-item > a:not(.external)
    &:hover, &.router-link-active
      margin-bottom -2px
      border-bottom 2px solid lighten($accentColor, 8%)
</style>


================================================
FILE: docs/.vuepress/theme/components/Navbar.vue
================================================
<template>
  <header class="navbar">
    <SidebarButton @toggle-sidebar="$emit('toggle-sidebar')"/>

    <router-link
      :to="$localePath"
      class="home-link"
    >
      <img
        class="logo"
        v-if="$site.themeConfig.logo"
        :src="$withBase($site.themeConfig.logo)"
        :alt="$siteTitle"
      >
      <span
        ref="siteName"
        class="site-name"
        v-if="$siteTitle"
        :class="{ 'can-hide': $site.themeConfig.logo }"
      >{{ $siteTitle }}</span>
    </router-link>

    <div
      class="links"
      :style="linksWrapMaxWidth ? {
        'max-width': linksWrapMaxWidth + 'px'
      } : {}"
    >
      <!-- <AlgoliaSearchBox
        v-if="isAlgoliaSearch"
        :options="algolia"
      /> -->
      <SearchBox v-if="$site.themeConfig.search !== false && $page.frontmatter.search !== false"/>
      <NavLinks class="can-hide"/>
    </div>
  </header>
</template>

<script>
import SidebarButton from './SidebarButton.vue'
// import AlgoliaSearchBox from '@AlgoliaSearchBox'
import SearchBox from '@SearchBox'
import NavLinks from './NavLinks.vue'

export default {
  components: { SidebarButton, NavLinks, SearchBox },

  data () {
    return {
      linksWrapMaxWidth: null
    }
  },

  mounted () {
    const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
    const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight'))
    const handleLinksWrapWidth = () => {
      if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
        this.linksWrapMaxWidth = null
      } else {
        this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING
          - (this.$refs.siteName && this.$refs.siteName.offsetWidth || 0)
      }
    }
    handleLinksWrapWidth()
    window.addEventListener('resize', handleLinksWrapWidth, false)
  },

  computed: {
    algolia () {
      return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
    },

    isAlgoliaSearch () {
      return this.algolia && this.algolia.apiKey && this.algolia.indexName
    }
  }
}

function css (el, property) {
  // NOTE: Known bug, will return 'auto' if style value is 'auto'
  const win = el.ownerDocument.defaultView
  // null means not to return pseudo styles
  return win.getComputedStyle(el, null)[property]
}
</script>

<style lang="stylus">
$navbar-vertical-padding = 0.7rem
$navbar-horizontal-padding = 1.5rem

.navbar
  padding $navbar-vertical-padding $navbar-horizontal-padding
  line-height $navbarHeight - 1.4rem
  a, span, img
    display inline-block
  .logo
    height $navbarHeight - 1.4rem
    min-width $navbarHeight - 1.4rem
    margin-right 0.8rem
    vertical-align top
  .site-name
    font-size 1.3rem
    font-weight 600
    color $textColor
    position relative
  .links
    padding-left 1.5rem
    box-sizing border-box
    background-color white
    white-space nowrap
    font-size 0.9rem
    position absolute
    right $navbar-horizontal-padding
    top $navbar-vertical-padding
    display flex
    .search-box
      flex: 0 0 auto
      vertical-align top

@media (max-width: $MQMobile)
  .navbar
    padding-left 4rem
    .can-hide
      display none
    .links
      padding-left 1.5rem
</style>


================================================
FILE: docs/.vuepress/theme/components/Page.vue
================================================
<template>
  <main class="page">
    <slot name="top"/>

    <Ads></Ads>

    <Content/>

    <footer class="page-edit">
      <div
        class="edit-link"
        v-if="editLink"
      >
        <a
          :href="editLink"
          target="_blank"
          rel="noopener noreferrer"
        >{{ editLinkText }}</a>
        <OutboundLink/>
      </div>

      <div
        class="last-updated"
        v-if="lastUpdated"
      >
        <span class="prefix">{{ lastUpdatedText }}: </span>
        <span class="time">{{ lastUpdated }}</span>
      </div>
    </footer>

    <div class="page-nav" v-if="prev || next">
      <p class="inner">
        <span
          v-if="prev"
          class="prev"
        >
          ←
          <router-link
            v-if="prev"
            class="prev"
            :to="prev.path"
          >
            {{ prev.title || prev.path }}
          </router-link>
        </span>

        <span
          v-if="next"
          class="next"
        >
          <router-link
            v-if="next"
            :to="next.path"
          >
            {{ next.title || next.path }}
          </router-link>
          →
        </span>
      </p>
    </div>

    <slot name="bottom"/>
  </main>
</template>

<script>
import { resolvePage, normalize, outboundRE, endingSlashRE } from '../util'
import Ads from './Ads.vue'

export default {
  props: ['sidebarItems'],

  components: {
    Ads
  },

  computed: {
    lastUpdated () {
      return this.$page.lastUpdated
    },

    lastUpdatedText () {
      if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {
        return this.$themeLocaleConfig.lastUpdated
      }
      if (typeof this.$site.themeConfig.lastUpdated === 'string') {
        return this.$site.themeConfig.lastUpdated
      }
      return 'Last Updated'
    },

    prev () {
      const prev = this.$page.frontmatter.prev
      if (prev === false) {
        return
      } else if (prev) {
        return resolvePage(this.$site.pages, prev, this.$route.path)
      } else {
        return resolvePrev(this.$page, this.sidebarItems)
      }
    },

    next () {
      const next = this.$page.frontmatter.next
      if (next === false) {
        return
      } else if (next) {
        return resolvePage(this.$site.pages, next, this.$route.path)
      } else {
        return resolveNext(this.$page, this.sidebarItems)
      }
    },

    editLink () {
      if (this.$page.frontmatter.editLink === false) {
        return
      }
      const {
        repo,
        editLinks,
        docsDir = '',
        docsBranch = 'master',
        docsRepo = repo
      } = this.$site.themeConfig

      let path = normalize(this.$page.path)
      if (endingSlashRE.test(path)) {
        path += 'README.md'
      } else {
        path += '.md'
      }
      if (docsRepo && editLinks) {
        return this.createEditLink(repo, docsRepo, docsDir, docsBranch, path)
      }
    },

    editLinkText () {
      return (
        this.$themeLocaleConfig.editLinkText
        || this.$site.themeConfig.editLinkText
        || `Edit this page`
      )
    }
  },

  methods: {
    createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
      const bitbucket = /bitbucket.org/
      if (bitbucket.test(repo)) {
        const base = outboundRE.test(docsRepo)
          ? docsRepo
          : repo
        return (
          base.replace(endingSlashRE, '')
           + `/src`
           + `/${docsBranch}`
           + (docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '')
           + path
           + `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
        )
      }

      const base = outboundRE.test(docsRepo)
        ? docsRepo
        : `https://github.com/${docsRepo}`

      return (
        base.replace(endingSlashRE, '')
        + `/edit/${docsBranch}`
        + (docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '')
        + path
      )
    }
  }
}

function resolvePrev (page, items) {
  return find(page, items, -1)
}

function resolveNext (page, items) {
  return find(page, items, 1)
}

function find (page, items, offset) {
  const res = []
  flattern(items, res)
  for (let i = 0; i < res.length; i++) {
    const cur = res[i]
    if (cur.type === 'page' && cur.path === decodeURIComponent(page.path)) {
      return res[i + offset]
    }
  }
}

function flattern (items, res) {
  for (let i = 0, l = items.length; i < l; i++) {
    if (items[i].type === 'group') {
      flattern(items[i].children || [], res)
    } else {
      res.push(items[i])
    }
  }
}

</script>

<style lang="stylus">
@require '../styles/wrapper.styl'

.page
  padding-bottom 2rem
  display block

.page-edit
  @extend $wrapper
  padding-top 1rem
  padding-bottom 1rem
  overflow auto
  .edit-link
    display inline-block
    a
      color lighten($textColor, 25%)
      margin-right 0.25rem
  .last-updated
    float right
    font-size 0.9em
    .prefix
      font-weight 500
      color lighten($textColor, 25%)
    .time
      font-weight 400
      color #aaa

.page-nav
  @extend $wrapper
  padding-top 1rem
  padding-bottom 0
  .inner
    min-height 2rem
    margin-top 0
    border-top 1px solid $borderColor
    padding-top 1rem
    overflow auto // clear float
  .next
    float right

@media (max-width: $MQMobile)
  .page-edit
    .edit-link
      margin-bottom .5rem
    .last-updated
      font-size .8em
      float none
      text-align left

</style>


================================================
FILE: docs/.vuepress/theme/components/Sidebar.vue
================================================
<template>
  <aside class="sidebar">
    <NavLinks/>
    <slot name="top"/>
    <Ads></Ads>
    <SidebarLinks :depth="0" :items="items"/>
    <slot name="bottom"/>
  </aside>
</template>

<script>
import SidebarLinks from './SidebarLinks.vue'
import NavLinks from './NavLinks.vue'
import Ads from './Ads.vue';

export default {
  name: 'Sidebar',

  components: { SidebarLinks, NavLinks, Ads },

  props: ['items']
}
</script>

<style lang="stylus">
.sidebar
  .ads
    display none
    position: initial
  ul
    padding 0
    margin 0
    list-style-type none
  a
    display inline-block
  .nav-links
    display none
    border-bottom 1px solid $borderColor
    padding 0.5rem 0 0.75rem 0
    a
      font-weight 600
    .nav-item, .repo-link
      display block
      line-height 1.25rem
      font-size 1.1em
      padding 0.5rem 0 0.5rem 1.5rem
  & > .sidebar-links
    padding 1.5rem 0
    & > li > a.sidebar-link
      font-size 1.1em
      line-height 1.7
      font-weight bold
    & > li:not(:first-child)
      margin-top .75rem

@media (max-width: $MQMobile)
  .sidebar
    .ads
      display block
      width 100%
      margin-top  1rem

      > div
        text-align left
        padding-left  1.5rem

    .nav-links
      display block
      .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
        top calc(1rem - 2px)
    & > .sidebar-links
      padding 1rem 0
</style>


================================================
FILE: docs/.vuepress/theme/components/SidebarButton.vue
================================================
<template>
  <div class="sidebar-button" @click="$emit('toggle-sidebar')">
    <svg class="icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512">
      <path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z" class=""></path>
    </svg>
  </div>
</template>

<style lang="stylus">
.sidebar-button
  cursor pointer
  display none
  width 1.25rem
  height 1.25rem
  position absolute
  padding 0.6rem
  top 0.6rem
  left 1rem
  .icon
    display block
    width 1.25rem
    height 1.25rem

@media (max-width: $MQMobile)
  .sidebar-button
    display block
</style>


================================================
FILE: docs/.vuepress/theme/components/SidebarGroup.vue
================================================
<template>
  <section
    class="sidebar-group"
    :class="[
      {
        collapsable,
        'is-sub-group': depth !== 0
      },
      `depth-${depth}`
    ]"
  >
    <router-link
      v-if="item.path"
      class="sidebar-heading clickable"
      :class="{
        open,
        'active': isActive($route, item.path)
      }"
      :to="item.path"
      @click.native="$emit('toggle')"
    >
      <span>{{ item.title }}</span>
      <span
        class="arrow"
        v-if="collapsable"
        :class="open ? 'down' : 'right'">
      </span>
    </router-link>

    <p
      v-else
      class="sidebar-heading"
      :class="{ open }"
      @click="$emit('toggle')"
    >
      <span>{{ item.title }}</span>
      <span
        class="arrow"
        v-if="collapsable"
        :class="open ? 'down' : 'right'">
      </span>
    </p>

    <DropdownTransition>
      <SidebarLinks
        class="sidebar-group-items"
        :items="item.children"
        v-if="open || !collapsable"
        :sidebarDepth="item.sidebarDepth"
        :depth="depth + 1"
      />
    </DropdownTransition>
  </section>
</template>

<script>
import { isActive } from '../util'
import DropdownTransition from './DropdownTransition.vue'

export default {
  name: 'SidebarGroup',
  props: ['item', 'open', 'collapsable', 'depth'],
  components: { DropdownTransition },
  // ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
  beforeCreate () {
    this.$options.components.SidebarLinks = require('./SidebarLinks.vue').default
  },
  methods: { isActive }
}
</script>

<style lang="stylus">
.sidebar-group
  .sidebar-group
    padding-left 0.5em
  &:not(.collapsable)
    .sidebar-heading:not(.clickable)
      cursor auto
      color inherit
  // refine styles of nested sidebar groups
  &.is-sub-group
    padding-left 0
    & > .sidebar-heading
      font-size 0.95em
      line-height 1.4
      font-weight normal
      padding-left 2rem
      &:not(.clickable)
        opacity 0.5
    & > .sidebar-group-items
      padding-left 1rem
      & > li > .sidebar-link
        font-size: 0.95em;
        border-left none
  &.depth-2
    & > .sidebar-heading
      border-left none

.sidebar-heading
  color $textColor
  transition color .15s ease
  cursor pointer
  font-size 1.1em
  font-weight bold
  // text-transform uppercase
  padding 0.35rem 1.5rem 0.35rem 1.25rem
  width 100%
  box-sizing border-box
  margin 0
  border-left 0.25rem solid transparent
  &.open, &:hover
    color inherit
  .arrow
    position relative
    top -0.12em
    left 0.5em
  &.clickable
    &.active
      font-weight 600
      color $accentColor
      border-left-color $accentColor
    &:hover
      color $accentColor

.sidebar-group-items
  transition height .1s ease-out
  font-size 0.95em
  overflow hidden
</style>


================================================
FILE: docs/.vuepress/theme/components/SidebarLink.vue
================================================
<script>
import { isActive, hashRE, groupHeaders } from '../util'

export default {
  functional: true,

  props: ['item', 'sidebarDepth'],

  render (h,
    {
      parent: {
        $page,
        $site,
        $route,
        $themeConfig,
        $themeLocaleConfig
      },
      props: {
        item,
        sidebarDepth
      }
    }) {
    // use custom active class matching logic
    // due to edge case of paths ending with / + hash
    const selfActive = isActive($route, item.path)
    // for sidebar: auto pages, a hash link should be active if one of its child
    // matches
    const active = item.type === 'auto'
      ? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
      : selfActive
    const link = renderLink(h, item.path, item.title || item.path, active)

    const configDepth = $page.frontmatter.sidebarDepth
      || sidebarDepth
      || $themeLocaleConfig.sidebarDepth
      || $themeConfig.sidebarDepth

    const maxDepth = configDepth == null ? 1 : configDepth

    const displayAllHeaders = $themeLocaleConfig.displayAllHeaders
      || $themeConfig.displayAllHeaders

    if (item.type === 'auto') {
      return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
    } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
      const children = groupHeaders(item.headers)
      return [link, renderChildren(h, children, item.path, $route, maxDepth)]
    } else {
      return link
    }
  }
}

function renderLink (h, to, text, active) {
  return h('router-link', {
    props: {
      to,
      activeClass: '',
      exactActiveClass: ''
    },
    class: {
      active,
      'sidebar-link': true
    }
  }, text)
}

function renderChildren (h, children, path, route, maxDepth, depth = 1) {
  if (!children || depth > maxDepth) return null
  return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
    const active = isActive(route, path + '#' + c.slug)
    return h('li', { class: 'sidebar-sub-header' }, [
      renderLink(h, path + '#' + c.slug, c.title, active),
      renderChildren(h, c.children, path, route, maxDepth, depth + 1)
    ])
  }))
}
</script>

<style lang="stylus">
.sidebar .sidebar-sub-headers
  padding-left 1rem
  font-size 0.95em

a.sidebar-link
  font-size 1em
  font-weight 400
  display inline-block
  color $textColor
  border-left 0.25rem solid transparent
  padding 0.35rem 1rem 0.35rem 1.25rem
  line-height 1.4
  width: 100%
  box-sizing: border-box
  &:hover
    color $accentColor
  &.active
    font-weight 600
    color $accentColor
    border-left-color $accentColor
  .sidebar-group &
    padding-left 2rem
  .sidebar-sub-headers &
    padding-top 0.25rem
    padding-bottom 0.25rem
    border-left none
    &.active
      font-weight 500
</style>


================================================
FILE: docs/.vuepress/theme/components/SidebarLinks.vue
================================================
<template>
  <ul
    class="sidebar-links"
    v-if="items.length"
  >
    <li v-for="(item, i) in items" :key="i">
      <SidebarGroup
        v-if="item.type === 'group'"
        :item="item"
        :open="i === openGroupIndex"
        :collapsable="item.collapsable || item.collapsible"
        :depth="depth"
        @toggle="toggleGroup(i)"
      />
      <SidebarLink
        v-else
        :sidebarDepth="sidebarDepth"
        :item="item"
      />
    </li>
  </ul>
</template>

<script>
import SidebarGroup from './SidebarGroup.vue'
import SidebarLink from './SidebarLink.vue'
import { isActive } from '../util'

export default {
  name: 'SidebarLinks',

  components: { SidebarGroup, SidebarLink },

  props: [
    'items',
    'depth',  // depth of current sidebar links
    'sidebarDepth' // depth of headers to be extracted
  ],

  data () {
    return {
      openGroupIndex: 0
    }
  },

  created () {
    this.refreshIndex()
  },

  watch: {
    '$route' () {
      this.refreshIndex()
    }
  },

  methods: {
    refreshIndex () {
      const index = resolveOpenGroupIndex(
        this.$route,
        this.items
      )
      if (index > -1) {
        this.openGroupIndex = index
      }
    },

    toggleGroup (index) {
      this.openGroupIndex = index === this.openGroupIndex ? -1 : index
    },

    isActive (page) {
      return isActive(this.$route, page.regularPath)
    }
  }
}

function resolveOpenGroupIndex (route, items) {
  for (let i = 0; i < items.length; i++) {
    const item = items[i]
    if (item.type === 'group' && item.children.some(c => c.type === 'page' && isActive(route, c.path))) {
      return i
    }
  }
  return -1
}
</script>


================================================
FILE: docs/.vuepress/theme/global-components/Badge.vue
================================================
<script>
export default {
  functional: true,
  props: {
    type: {
      type: String,
      default: 'tip'
    },
    text: String,
    vertical: {
      type: String,
      default: 'top'
    }
  },
  render (h, { props, slots }) {
    return h('span', {
      class: ['badge', props.type, props.vertical]
    }, props.text || slots().default)
  }
}
</script>

<style lang="stylus" scoped>
.badge
  display inline-block
  font-size 14px
  height 18px
  line-height 18px
  border-radius 3px
  padding 0 6px
  color white
  margin-right 5px
  background-color #42b983
  &.middle
    vertical-align middle
  &.top
    vertical-align top
  &.tip, &.green
    background-color #42b983
  &.error
    background-color #DA5961 //#f66
  &.warning, &.warn, &.yellow
    background-color darken(#ffe564, 35%)
</style>


================================================
FILE: docs/.vuepress/theme/index.js
================================================
const path = require('path');

// Theme API.
module.exports = (options, ctx) => ({
  alias() {
    const { themeConfig, siteConfig } = ctx;
    // resolve algolia
    const isAlgoliaSearch =
      themeConfig.algolia ||
      Object.keys((siteConfig.locales && themeConfig.locales) || {}).some(base => themeConfig.locales[base].algolia);
    return {
      '@AlgoliaSearchBox': isAlgoliaSearch
        ? path.resolve(__dirname, 'components/AlgoliaSearchBox.vue')
        : path.resolve(__dirname, 'noopModule.js')
    };
  },

  plugins: [
    '@vuepress/active-header-links',
    '@vuepress/search',
    '@vuepress/plugin-nprogress',
    ['@vuepress/container', { type: 'tip' }],
    ['@vuepress/container', { type: 'warning' }],
    ['@vuepress/container', { type: 'danger' }]
  ]
});


================================================
FILE: docs/.vuepress/theme/layouts/404.vue
================================================
<template>
  <div class="theme-container">
    <div class="content">
      <h1>404</h1>
      <blockquote>{{ getMsg() }}</blockquote>
      <router-link to="/">Take me home.</router-link>
    </div>
  </div>
</template>

<script>
const msgs = [
  `There's nothing here.`,
  `How did we get here?`,
  `That's a Four-Oh-Four.`,
  `Looks like we've got some broken links.`
]

export default {
  methods: {
    getMsg () {
      return msgs[Math.floor(Math.random() * msgs.length)]
    }
  }
}
</script>

<style src="../styles/theme.styl" lang="stylus"></style>


================================================
FILE: docs/.vuepress/theme/layouts/Layout.vue
================================================
<template>
  <div
    class="theme-container"
    :class="pageClasses"
    @touchstart="onTouchStart"
    @touchend="onTouchEnd"
  >
    <Navbar
      v-if="shouldShowNavbar"
      @toggle-sidebar="toggleSidebar"
    />

    <div
      class="sidebar-mask"
      @click="toggleSidebar(false)"
    ></div>

    <Sidebar
      :items="sidebarItems"
      @toggle-sidebar="toggleSidebar"
    >
      <slot
        name="sidebar-top"
        slot="top"
      />
      <slot
        name="sidebar-bottom"
        slot="bottom"
      />
    </Sidebar>

    <Home v-if="$page.frontmatter.home"/>

    <Page
      v-else
      :sidebar-items="sidebarItems"
    >
      <slot
        name="page-top"
        slot="top"
      />
      <slot
        name="page-bottom"
        slot="bottom"
      />
    </Page>
  </div>
</template>

<script>
import Home from '../components/Home.vue'
import Navbar from '../components/Navbar.vue'
import Page from '../components/Page.vue'
import Sidebar from '../components/Sidebar.vue'
import { resolveSidebarItems } from '../util'

export default {
  components: { Home, Page, Sidebar, Navbar },

  data () {
    return {
      isSidebarOpen: false
    }
  },

  computed: {
    shouldShowNavbar () {
      const { themeConfig } = this.$site
      const { frontmatter } = this.$page
      if (
        frontmatter.navbar === false
        || themeConfig.navbar === false) {
        return false
      }
      return (
        this.$title
        || themeConfig.logo
        || themeConfig.repo
        || themeConfig.nav
        || this.$themeLocaleConfig.nav
      )
    },

    shouldShowSidebar () {
      const { frontmatter } = this.$page
      return (
        !frontmatter.home
        && frontmatter.sidebar !== false
        && this.sidebarItems.length
      )
    },

    sidebarItems () {
      return resolveSidebarItems(
        this.$page,
        this.$page.regularPath,
        this.$site,
        this.$localePath
      )
    },

    pageClasses () {
      const userPageClass = this.$page.frontmatter.pageClass
      return [
        {
          'no-navbar': !this.shouldShowNavbar,
          'sidebar-open': this.isSidebarOpen,
          'no-sidebar': !this.shouldShowSidebar
        },
        userPageClass
      ]
    }
  },

  mounted () {
    this.$router.afterEach(() => {
      this.isSidebarOpen = false
    })
  },

  methods: {
    toggleSidebar (to) {
      this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
    },

    // side swipe
    onTouchStart (e) {
      this.touchStart = {
        x: e.changedTouches[0].clientX,
        y: e.changedTouches[0].clientY
      }
    },

    onTouchEnd (e) {
      const dx = e.changedTouches[0].clientX - this.touchStart.x
      const dy = e.changedTouches[0].clientY - this.touchStart.y
      if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
        if (dx > 0 && this.touchStart.x <= 80) {
          this.toggleSidebar(true)
        } else {
          this.toggleSidebar(false)
        }
      }
    }
  }
}
</script>

<style src="prismjs/themes/prism-tomorrow.css"></style>
<style src="../styles/theme.styl" lang="stylus"></style>


================================================
FILE: docs/.vuepress/theme/styles/arrow.styl
================================================
@require './config'

.arrow
  display inline-block
  width 0
  height 0
  &.up
    border-left 4px solid transparent
    border-right 4px solid transparent
    border-bottom 6px solid $arrowBgColor
  &.down
    border-left 4px solid transparent
    border-right 4px solid transparent
    border-top 6px solid $arrowBgColor
  &.right
    border-top 4px solid transparent
    border-bottom 4px solid transparent
    border-left 6px solid $arrowBgColor
  &.left
    border-top 4px solid transparent
    border-bottom 4px solid transparent
    border-right 6px solid $arrowBgColor


================================================
FILE: docs/.vuepress/theme/styles/code.styl
================================================
.content
  code
    color lighten($textColor, 20%)
    padding 0.25rem 0.5rem
    margin 0
    font-size 0.85em
    background-color rgba(27,31,35,0.05)
    border-radius 3px
    .token
      &.deleted
        color #EC5975
      &.inserted
        color $accentColor

.content
  pre, pre[class*="language-"]
    line-height 1.4
    padding 1.25rem 1.5rem
    margin 0.85rem 0
    background-color $codeBgColor
    border-radius 6px
    overflow auto
    code
      color #fff
      padding 0
      background-color transparent
      border-radius 0

div[class*="language-"]
  position relative
  background-color $codeBgColor
  border-radius 6px
  .highlight-lines
    user-select none
    padding-top 1.3rem
    position absolute
    top 0
    left 0
    width 100%
    line-height 1.4
    .highlighted
      background-color rgba(0, 0, 0, 66%)
  pre, pre[class*="language-"]
    background transparent
    position relative
    z-index 1
  &::before
    position absolute
    z-index 3
    top 0.8em
    right 1em
    font-size 0.75rem
    color rgba(255, 255, 255, 0.4)
  &:not(.line-numbers-mode)
    .line-numbers-wrapper
      display none
  &.line-numbers-mode
    .highlight-lines .highlighted
        position relative
        &:before
          content ' '
          position absolute
          z-index 3
          left 0
          top 0
          display block
          width $lineNumbersWrapperWidth
          height 100%
          background-color rgba(0, 0, 0, 66%)
    pre
      padding-left $lineNumbersWrapperWidth + 1 rem
      vertical-align middle
    .line-numbers-wrapper
      position absolute
      top 0
      width $lineNumbersWrapperWidth
      text-align center
      color rgba(255, 255, 255, 0.3)
      padding 1.25rem 0
      line-height 1.4
      br
        user-select none
      .line-number
        position relative
        z-index 4
        user-select none
        font-size 0.85em
    &::after
      content ''
      position absolute
      z-index 2
      top 0
      left 0
      width $lineNumbersWrapperWidth
      height 100%
      border-radius 6px 0 0 6px
      border-right 1px solid rgba(0, 0, 0, 66%)
      background-color $codeBgColor


for lang in $codeLang
  div{'[class~="language-' + lang + '"]'}
    &:before
      content ('' + lang)

div[class~="language-javascript"]
  &:before
    content "js"

div[class~="language-typescript"]
  &:before
    content "ts"

div[class~="language-markup"]
  &:before
    content "html"

div[class~="language-markdown"]
  &:before
    content "md"

div[class~="language-json"]:before
  content "json"

div[class~="language-ruby"]:before
  content "rb"

div[class~="language-python"]:before
  content "py"

div[class~="language-bash"]:before
  content "sh"

div[class~="language-php"]:before
  content "php"


================================================
FILE: docs/.vuepress/theme/styles/custom-blocks.styl
================================================
.custom-block
  .custom-block-title
    font-weight 600
    margin-bottom -0.4rem
  &.tip, &.warning, &.danger
    padding .1rem 1.5rem
    border-left-width .5rem
    border-left-style solid
    margin 1rem 0
  &.tip
    background-color #f3f5f7
    border-color #42b983
  &.warning
    background-color rgba(255,229,100,.3)
    border-color darken(#ffe564, 35%)
    color darken(#ffe564, 70%)
    .custom-block-title
      color darken(#ffe564, 50%)
    a
      color $textColor
  &.danger
    background-color #ffe6e6
    border-color darken(red, 20%)
    color darken(red, 70%)
    .custom-block-title
      color darken(red, 40%)
    a
      color $textColor

pre.vue-container
  border-left-width: .5rem;
  border-left-style: solid;
  border-color: #42b983;
  border-radius: 0px;
  & > code
    font-size: 14px !important;
    & > p
      margin: -5px 0 -20px 0;
    code
      background-color: #42b983 !important;
      padding: 3px 5px;
      border-radius: 3px;
      color #000
    em
      color #808080
      font-weight light



================================================
FILE: docs/.vuepress/theme/styles/mobile.styl
================================================
@require './config'

$mobileSidebarWidth = $sidebarWidth * 0.82

// narrow desktop / iPad
@media (max-width: $MQNarrow)
  .sidebar
    font-size 15px
    width $mobileSidebarWidth
  .page
    padding-left $mobileSidebarWidth

// wide mobile
@media (max-width: $MQMobile)
  .sidebar
    top 0
    padding-top $navbarHeight
    transform translateX(-100%)
    transition transform .2s ease
  .page
    padding-left 0
  .theme-container
    &.sidebar-open
      .sidebar
        transform translateX(0)
    &.no-navbar
      .sidebar
        padding-top: 0

// narrow mobile
@media (max-width: $MQMobileNarrow)
  h1
    font-size 1.9rem
  .content
    div[class*="language-"]
      margin 0.85rem -1.5rem
      border-radius 0


================================================
FILE: docs/.vuepress/theme/styles/theme.styl
================================================
@require './code'
@require './custom-blocks'
@require './arrow'
@require './wrapper'
@require './toc'

html, body
  padding 0
  margin 0
  background-color #fff

body
  font-family -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif
  -webkit-font-smoothing antialiased
  -moz-osx-font-smoothing grayscale
  font-size 16px
  color $textColor

.page
  padding-left $sidebarWidth

.navbar
  position fixed
  z-index 20
  top 0
  left 0
  right 0
  height $navbarHeight
  background-color #fff
  box-sizing border-box
  border-bottom 1px solid $borderColor

.sidebar-mask
  position fixed
  z-index 9
  top 0
  left 0
  width 100vw
  height 100vh
  display none

.sidebar
  font-size 16px
  background-color #fff
  width $sidebarWidth
  position fixed
  z-index 10
  margin 0
  top $navbarHeight
  left 0
  bottom 0
  box-sizing border-box
  border-right 1px solid $borderColor
  overflow-y auto

.content:not(.custom)
  @extend $wrapper
  > *:first-child
    margin-top $navbarHeight
  a:hover
    text-decoration underline
  p.demo
    padding 1rem 1.5rem
    border 1px solid #ddd
    border-radius 4px
  img
    max-width 100%

.content.custom
  padding 0
  margin 0
  img
    max-width 100%

a
  font-weight 500
  color $accentColor
  text-decoration none

p a code
  font-weight 400
  color $accentColor

kbd
  background #eee
  border solid 0.15rem #ddd
  border-bottom solid 0.25rem #ddd
  border-radius 0.15rem
  padding 0 0.15em

blockquote
  font-size .9rem
  color #999
  border-left .5rem solid #dfe2e5
  margin 0.5rem 0
  padding .25rem 0 .25rem 1rem
  & > p
    margin 0

ul, ol
  padding-left 1.2em

strong
  font-weight 600

h1, h2, h3, h4, h5, h6
  font-weight 600
  line-height 1.25
  .content:not(.custom) > &
    margin-top (0.5rem - $navbarHeight)
    padding-top ($navbarHeight + 1rem)
    margin-bottom 0
    &:first-child
      margin-top -1.5rem
      margin-bottom 1rem
      + p, + pre, + .custom-block
        margin-top 2rem
  &:hover .header-anchor
    opacity: 1

h1
  font-size 2.2rem

h2
  font-size 1.65rem
  padding-bottom .3rem
  border-bottom 1px solid $borderColor

h3
  font-size 1.35rem

a.header-anchor
  font-size 0.85em
  float left
  margin-left -0.87em
  padding-right 0.23em
  margin-top 0.125em
  opacity 0
  &:hover
    text-decoration none

code, kbd, .line-number
  font-family source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace

p, ul, ol
  line-height 1.7

hr
  border 0
  border-top 1px solid $borderColor

table
  border-collapse collapse
  margin 1rem 0
  display: block
  overflow-x: auto

tr
  border-top 1px solid #dfe2e5
  &:nth-child(2n)
    background-color #f6f8fa

th, td
  border 1px solid #dfe2e5
  padding .6em 1em

.theme-container
  &.sidebar-open
    .sidebar-mask
      display: block
  &.no-navbar
    .content:not(.custom) > h1, h2, h3, h4, h5, h6
        margin-top 1.5rem
        padding-top 0
    .sidebar
      top 0


@media (min-width: ($MQMobile + 1px))
  .theme-container.no-sidebar
    .sidebar
      display none
    .page
      padding-left 0

@require 'mobile.styl'


================================================
FILE: docs/.vuepress/theme/styles/toc.styl
================================================
.table-of-contents
  .badge
    vertical-align middle


================================================
FILE: docs/.vuepress/theme/styles/wrapper.styl
================================================
$wrapper
  max-width $contentWidth
  // margin 0 2rem
  padding 2rem 2.5rem
  @media (max-width: $MQNarrow)
    padding 2rem
  @media (max-width: $MQMobileNarrow)
    padding 1.5rem



================================================
FILE: docs/.vuepress/theme/util/index.js
================================================
export const hashRE = /#.*$/;
export const extRE = /\.(md|html)$/;
export const endingSlashRE = /\/$/;
export const outboundRE = /^(https?:|mailto:|tel:)/;

export function normalize(path) {
  return decodeURI(path)
    .replace(hashRE, '')
    .replace(extRE, '');
}

export function getHash(path) {
  const match = path.match(hashRE);
  if (match) {
    return match[0];
  }
}

export function isExternal(path) {
  return outboundRE.test(path);
}

export function isMailto(path) {
  return /^mailto:/.test(path);
}

export function isTel(path) {
  return /^tel:/.test(path);
}

export function ensureExt(path) {
  if (isExternal(path)) {
    return path;
  }
  const hashMatch = path.match(hashRE);
  const hash = hashMatch ? hashMatch[0] : '';
  const normalized = normalize(path);

  if (endingSlashRE.test(normalized)) {
    return path;
  }
  return normalized + '.html' + hash;
}

export function isActive(route, path) {
  const routeHash = route.hash;
  const linkHash = getHash(path);
  if (linkHash && routeHash !== linkHash) {
    return false;
  }
  const routePath = normalize(route.path);
  const pagePath = normalize(path);
  return routePath === pagePath;
}

export function resolvePage(pages, rawPath, base) {
  if (base) {
    rawPath = resolvePath(rawPath, base);
  }
  const path = normalize(rawPath);
  for (let i = 0; i < pages.length; i++) {
    if (normalize(pages[i].regularPath) === path) {
      return Object.assign({}, pages[i], {
        type: 'page',
        path: ensureExt(pages[i].path)
      });
    }
  }
  console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`);
  return {};
}

function resolvePath(relative, base, append) {
  const firstChar = relative.charAt(0);
  if (firstChar === '/') {
    return relative;
  }

  if (firstChar === '?' || firstChar === '#') {
    return base + relative;
  }

  const stack = base.split('/');

  // remove trailing segment if:
  // - not appending
  // - appending to trailing slash (last segment is empty)
  if (!append || !stack[stack.length - 1]) {
    stack.pop();
  }

  // resolve relative path
  const segments = relative.replace(/^\//, '').split('/');
  for (let i = 0; i < segments.length; i++) {
    const segment = segments[i];
    if (segment === '..') {
      stack.pop();
    } else if (segment !== '.') {
      stack.push(segment);
    }
  }

  // ensure leading slash
  if (stack[0] !== '') {
    stack.unshift('');
  }

  return stack.join('/');
}

/**
 * @param { Page } page
 * @param { string } regularPath
 * @param { SiteData } site
 * @param { string } localePath
 * @returns { SidebarGroup }
 */
export function resolveSidebarItems(page, regularPath, site, localePath) {
  const { pages, themeConfig } = site;

  const localeConfig = localePath && themeConfig.locales ? themeConfig.locales[localePath] || themeConfig : themeConfig;

  const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar;
  if (pageSidebarConfig === 'auto') {
    return resolveHeaders(page);
  }

  const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar;
  if (!sidebarConfig) {
    return [];
  } else {
    const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig);
    return config ? config.map(item => resolveItem(item, pages, base)) : [];
  }
}

/**
 * @param { Page } page
 * @returns { SidebarGroup }
 */
function resolveHeaders(page) {
  const headers = groupHeaders(page.headers || []);
  return [
    {
      type: 'group',
      collapsable: false,
      title: page.title,
      path: null,
      children: headers.map(h => ({
        type: 'auto',
        title: h.title,
        basePath: page.path,
        path: page.path + '#' + h.slug,
        children: h.children || []
      }))
    }
  ];
}

export function groupHeaders(headers) {
  // group h3s under h2
  headers = headers.map(h => Object.assign({}, h));
  let lastH2;
  headers.forEach(h => {
    if (h.level === 2) {
      lastH2 = h;
    } else if (lastH2) {
      (lastH2.children || (lastH2.children = [])).push(h);
    }
  });
  return headers.filter(h => h.level === 2);
}

export function resolveNavLinkItem(linkItem) {
  return Object.assign(linkItem, {
    type: linkItem.items && linkItem.items.length ? 'links' : 'link'
  });
}

/**
 * @param { Route } route
 * @param { Array<string|string[]> | Array<SidebarGroup> | [link: string]: SidebarConfig } config
 * @returns { base: string, config: SidebarConfig }
 */
export function resolveMatchingConfig(regularPath, config) {
  if (Array.isArray(config)) {
    return {
      base: '/',
      config: config
    };
  }
  for (const base in config) {
    if (ensureEndingSlash(regularPath).indexOf(base) === 0) {
      return {
        base,
        config: config[base]
      };
    }
  }
  return {};
}

function ensureEndingSlash(path) {
  return /(\.html|\/)$/.test(path) ? path : path + '/';
}

function resolveItem(item, pages, base, groupDepth = 1) {
  if (typeof item === 'string') {
    return resolvePage(pages, item, base);
  } else if (Array.isArray(item)) {
    return Object.assign(resolvePage(pages, item[0], base), {
      title: item[1]
    });
  } else {
    if (groupDepth > 3) {
      console.error('[vuepress] detected a too deep nested sidebar group.');
    }
    const children = item.children || [];
    if (children.length === 0 && item.path) {
      return Object.assign(resolvePage(pages, item.path, base), {
        title: item.title
      });
    }
    return {
      type: 'group',
      path: item.path,
      title: item.title,
      sidebarDepth: item.sidebarDepth,
      children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)),
      collapsable: item.collapsable !== false
    };
  }
}


================================================
FILE: docs/README.md
================================================
# 深入理解 TypeScript

此书是 [《TypeScript Deep Dive》](https://github.com/basarat/typescript-book/) 的中文翻译版,感谢作者 [Basarat](https://github.com/basarat) 的付出。

如果你喜欢纸质书籍,可以通过[京东](https://item.jd.com/12755624.html)或者[当当](http://product.m.dangdang.com/28487648.html?t=1574581821),来购买此书。

你可以通过订阅该[公众号](https://cdn.jkchao.cn/nuxt/img/14958af.jpg),来获取更多有趣的内容。

## Why

<img :src="$withBase('/typescript-downloads.jpg')" alt="ide"/>

> 数据来源:[npm 包下载量](https://npm-stat.com/charts.html?package=typescript&from=2016-01-01&to=2018-07-31)

如你所见,TypeScript 发展至今,已经成为大型项目的标配,其提供的静态类型系统,大大增强了代码的可读性以及可维护性;同时,它提供最新和不断发展的 JavaScript 特性,能让我们建立更健壮的组件。

[《TypeScript Deep Dive》](https://github.com/basarat/typescript-book/) 是一本很好的开源书,从基础到深入,很全面的阐述了 TypeScript 的各种魔法,不管你是新手,还是老鸟,它都将适应你。此外,它不同于 TypeScript 官方给出的文档(当然 TypeScript 给出的文档是很好的),在此书中,结合实际应用下的场景用例,你将能更深入的理解 TypeScript。

如今社区已经存在部分翻译,但都似乎已经停止更新。

于是在某天的某个冲动之下,这个 RP 就诞生了。

## 翻译内容

《TypeScript Deep Dive》 书中包含一部分 JavaScript Future 和一些其他的内容,在这里,我们并不打算翻译它,如果你有兴趣,可以查看原书中 [JavaScript Future](https://basarat.gitbooks.io/typescript/content/docs/future-javascript.html) 的有关章节。

由于 TypeScript 更新频繁,在此书中,我也将加入一些原书中并没有涉及到的知识点,希望和大家相互学习,一起进步。

此外,在不违背原作者本意前提下,为了更直观的表达,部分内容将采用意译,而非直译。

## How to contribute

你可以:

- 通过 PR 修改错别字,或者错误的格式;
- 发 issue 讨论文章中出现的一些不合理地方;
- 翻译 TODO 文件夹下的文章,并顺手 Email 我。

希望你在翻译或者 PR 之前,阅读[中文文章排版指北](https://github.com/mzlogin/chinese-copywriting-guidelines)。

## 最后

如果你和我一样对 TypeScript 充满兴趣,可以订阅(star)本项目,及时收到有关于此项目的更新。

如果你对文章有任何疑问,欢迎提交 [issues](https://github.com/jkchao/typescript-book-chinese/issues) 和我交流。

如果你认为有些地方翻译不够准确,或者你想补充一些文中没提到但是非常有意思的知识点,欢迎 [PR](https://github.com/jkchao/typescript-book-chinese/pulls)。

公众号:

<img :src="$withBase('/qrcode.jpg')" width="200" alt="支付宝">


================================================
FILE: docs/compiler/ast.md
================================================
# 抽象语法树

### Node 节点

节点是抽象语法树(AST) 的基本构造块。语法上,通常 `Node` 表示非末端(non-terminals)节点。但是,有些末端节点,如:标识符和字面量也会保留在树中。

AST 节点文档由两个关键部分构成。一是节点的 `SyntaxKind` 枚举,用于标识 AST 中的类型。二是其接口,即实例化 AST 时节点提供的 API。

这里是 `interface Node` 的一些关键成员:

- `TextRange` 标识该节点在源文件中的起止位置。
- `parent?: Node` 当前节点(在 AST 中)的父节点

`Node` 还有一些其他的成员,标志(flags)和修饰符(modifiers)等。你可以在源码中搜索 `interface Node` 来查看,而上面提到对节点的遍历是非常重要的。

### SourceFile

- `SyntaxKind.SourceFile`
- `interface SourceFile`.

每个 `SourceFile` 都是一棵 AST 的顶级节点,它们包含在 `Program` 中。

## AST 技巧:访问子节点

有个工具函数 `ts.forEachChild`,可以用来访问 AST 任一节点的所有子节点。

下面是简化的代码片段,用于演示如何工作:

```ts
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T {
    if (!node) {
        return;
    }
    switch (node.kind) {
        case SyntaxKind.BinaryExpression:
            return visitNode(cbNode, (<BinaryExpression>node).left) ||
                visitNode(cbNode, (<BinaryExpression>node).operatorToken) ||
                visitNode(cbNode, (<BinaryExpression>node).right);
        case SyntaxKind.IfStatement:
            return visitNode(cbNode, (<IfStatement>node).expression) ||
                visitNode(cbNode, (<IfStatement>node).thenStatement) ||
                visitNode(cbNode, (<IfStatement>node).elseStatement);

        // .... 更多
```

该函数主要检查 `node.kind` 并据此判断 node 的接口,然后在其子节点上调用 `cbNode`。但是,要注意该函数不会为*所有*子节点调用 `visitNode`(例如:SyntaxKind.SemicolonToken)。想获得某 AST 节点的*所有*子节点,只要调用该节点的成员函数 `.getChildren`。

如下函数会打印 AST 节点详细信息:

```ts
function printAllChildren(node: ts.Node, depth = 0) {
  console.log(new Array(depth + 1).join('----'), ts.syntaxKindToName(node.kind), node.pos, node.end);
  depth++;
  node.getChildren().forEach(c => printAllChildren(c, depth));
}
```

我们进一步讨论解析器时会看到该函数的使用示例。

## AST 技巧:SyntaxKind 枚举

`SyntaxKind` 被定义为一个常量枚举,如下所示:

```ts
export const enum SyntaxKind {
    Unknown,
    EndOfFileToken,
    SingleLineCommentTrivia,
    // ... 更多
```

这是个[常量枚举](../typings/enums.md#常量枚举),方便*内联*(例如:`ts.SyntaxKind.EndOfFileToken` 会变为 `1`),这样在使用 AST 时就不会有处理引用的额外开销。但编译时需要使用 --preserveConstEnums 编译标志,以便枚举*在运行时仍可用*。JavaScript 中你也可以根据需要使用 `ts.SyntaxKind.EndOfFileToken`。另外,可以用以下函数,将枚举成员转化为可读的字符串:

```ts
export function syntaxKindToName(kind: ts.SyntaxKind) {
  return (<any>ts).SyntaxKind[kind];
}
```

## AST 杂项

杂项(Trivia)是指源文本中对正常理解代码不太重要的部分,例如:空白,注释,冲突标记。(为了保持轻量)杂项*不会存储*在 AST 中。但是可以*视需要*使用一些 `ts.*` API 来获取。

展示这些 API 前,你需要理解以下内容:

### 杂项的所有权

通常:

- token 拥有它后面 _同一行_ 到下一个 token 之前的所有杂项
- 该行之后的注释都与下个的 token 相关

对于文件中的前导(leading)和结束(ending)注释:

- 源文件中的第一个 token 拥有所有开始的杂项
- 而文件最后的一些列杂项则附加到文件结束符上,该 token 长度为 0

### 杂项 API

注释在多数基本使用中,都是让人关注的杂项。节点的注释可以通过以下函数获取:

| 函数                          | 描述                                                                                                                    |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `ts.getLeadingCommentRanges`  | 给定源文本及其位置,返回给定位置后第一个换行符到 token 本身之间的注释范围(可能需要结合 `ts.Node.getFullStart` 使用)。 |
| `ts.getTrailingCommentRanges` | 给定源文本及其位置,返回给定位置后第一个换行符之前的注释范围(可能需要结合 `ts.Node.getEnd` 使用)。                    |

假设下面是某个源文件的一部分:

```ts
debugger;/*hello*/
    //bye
  /*hi*/    function
```

对 `function` 而言,`getLeadingCommentRanges` 仅返回最后的两个注释 `//bye` 和 `/*hi*/`。
另外,而在 `debugger` 语句结束位置调用 `getTrailingCommentRanges` 会得到注释 `/*hello*/`。

### Token Start 和 Full Start 位置

节点有所谓的 "token start" 和 "full start" 位置。

- Token Start:比较自然的版本,即文件中一个 token 的文本开始的位置。
- Full Start:是指扫描器从上一个重要 token 开始扫描的位置。

AST 节点有 `getStart` 和 `getFullStart` API 用于获取以上两种位置,还是这个例子:

```ts
debugger;/*hello*/
    //bye
  /*hi*/    function
```

对 `function` 而言,token start 即 `function` 的位置,而 _full_ start 是 `/*hello*/` 的位置。要注意,full start 甚至会包含前一节点拥有的杂项。


================================================
FILE: docs/compiler/binder.md
================================================
# 绑定器

大多数的 JavaScript 转译器(transpiler)都比 TypeScript 简单,因为它们几乎没提供代码分析的方法。典型的 JavaScript 转换器只有以下流程:

```
源码 ~~扫描器~~> Tokens ~~解析器~~> AST ~~发射器~~> JavaScript
```

上述架构确实对于简化 TypeScript 生成 JavaScript 的理解有帮助,但缺失了一个关键功能,即 TypeScript 的*语义*系统。为了协助(检查器执行)类型检查,绑定器将源码的各部分连接成一个相关的类型系统,供检查器使用。绑定器的主要职责是创建*符号*(Symbols)。

### 符号

符号将 AST 中的声明节点与其它声明连接到相同的实体上。符号是语义系统的基本构造块。符号的构造器定义在 `core.ts`(绑定器实际上通过 `objectAllocator.getSymbolConstructor` 来获取构造器)。下面是符号构造器:

```ts
function Symbol(flags: SymbolFlags, name: string) {
  this.flags = flags;
  this.name = name;
  this.declarations = undefined;
}
```

`SymbolFlags` 符号标志是个标志枚举,用于识别额外的符号类别(例如:变量作用域标志 `FunctionScopedVariable` 或 `BlockScopedVariable` 等)

### 检查器对绑定器的使用

实际上,绑定器被检查器在内部调用,而检查器又被程序调用。简化的调用栈如下所示:

```
program.getTypeChecker ->
    ts.createTypeChecker(检查器中)->
        initializeTypeChecker(检查器中) ->
            for each SourceFile `ts.bindSourceFile`(绑定器中)
            // followed by
            for each SourceFile `ts.mergeSymbolTable`(检查器中)
```

SourceFile 是绑定器的工作单元,`binder.ts` 由 `checker.ts` 驱动。

## 绑定器函数

`bindSourceFile` 和 `mergeSymbolTable` 是两个关键的绑定器函数,我们来看下:

### `bindSourceFile`

该函数主要是检查 `file.locals` 是否定义,如果没有则交给(本地函数) `bind` 来处理。

注意:`locals` 定义在节点上,其类型为 `SymbolTable`。`SourceFile` 也是一个节点(事实上是 AST 中的根节点)。

提示:TypeScript 编译器大量使用本地函数。本地函数很可能使用来自父函数的变量(通过闭包捕获)。例如 `bind` 是 `bindSourceFile` 中的一个本地函数,它或它调用的函数会设置 `symbolCount` 和 `classifiableNames` 等状态,然后将其存在返回的 `SourceFile` 中

### `bind`

bind 能处理任一节点(不只是 `SourceFile`),它做的第一件事是分配 `node.parent`(如果 `parent` 变量已设置,绑定器在 `bindChildren` 函数的处理中仍会再次设置), 然后交给 `bindWorker` 做很多*重*活。最后调用 `bindChildren`(该函数简单地将绑定器的状态(如:`parent`)存入函数本地变量中,接着在每个子节点上调用 `bind`,然后再将状态转存回绑定器中)。现在我们看下 `bindWorker`,一个更有趣的函数。

### `bindWorker`

该函数依据 `node.kind`(`SyntaxKind`类型)进行切换,并将工作委托给合适的 `bindXXX` 函数(也定义在`binder.ts`中)。例如:如果该节点是 `SourceFile` 则(最终且仅当节点是外部文件模块时)调用 `bindAnonymousDeclaration`

### `bindXXX` 函数

`bindXXX` 系函数有一些通用的模式和工具函数。其中最常用的一个是 `createSymbol` 函数,全部代码展示如下:

```ts
function createSymbol(flags: SymbolFlags, name: string): Symbol {
  symbolCount++;
  return new Symbol(flags, name);
}
```

如您所见,它简单地更新 `symbolCount`(一个 `bindSourceFile` 的本地变量),并使用指定的参数创建符号。

## 绑定器声明

### 符号与声明

节点和符号间的链接由几个函数执行。其中一个用于绑定 `SourceFile` 节点到源文件符号(外部模块的情况下)的函数是 `addDeclarationToSymbol`

注意:外部模块源文件的符号设置方式是 `flags : SymbolFlags.ValueModule` 和 `name: '"' + removeFileExtension(file.fileName) + '"'`.

```ts
function addDeclarationToSymbol(symbol: Symbol, node: Declaration, symbolFlags: SymbolFlags) {
  symbol.flags |= symbolFlags;

  // 创建 AST 节点到 symbol 的连接
  node.symbol = symbol;

  if (!symbol.declarations) {
    symbol.declarations = [];
  }
  // 将该节点添加为该符号的一个声明
  symbol.declarations.push(node);

  if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) {
    symbol.exports = {};
  }

  if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) {
    symbol.members = {};
  }

  if (symbolFlags & SymbolFlags.Value && !symbol.valueDeclaration) {
    symbol.valueDeclaration = node;
  }
}
```

上述代码主要执行的操作如下:

- 创建一个从 AST 节点到符号的链接(`node.symbol`)
- 将节点添加为该符号的*一个*声明

### 声明

声明就是一个有可选的名字的节点。下面是 `types.ts` 中的定义:

```ts
interface Declaration extends Node {
  _declarationBrand: any;
  name?: DeclarationName;
}
```

## 绑定器容器

AST 的节点可以被当作容器。这决定了节点及相关符号的 `SymbolTables` 的类别。容器是个抽象概念(没有相关的数据结构)。该概念由一些东西决定,`ContainerFlags` 枚举是其中之一。函数 `getContainerFlags`(位于 `binder.ts`) 驱动此标志,如下所示:

```ts
function getContainerFlags(node: Node): ContainerFlags {
  switch (node.kind) {
    case SyntaxKind.ClassExpression:
    case SyntaxKind.ClassDeclaration:
    case SyntaxKind.InterfaceDeclaration:
    case SyntaxKind.EnumDeclaration:
    case SyntaxKind.TypeLiteral:
    case SyntaxKind.ObjectLiteralExpression:
      return ContainerFlags.IsContainer;

    case SyntaxKind.CallSignature:
    case SyntaxKind.ConstructSignature:
    case SyntaxKind.IndexSignature:
    case SyntaxKind.MethodDeclaration:
    case SyntaxKind.MethodSignature:
    case SyntaxKind.FunctionDeclaration:
    case SyntaxKind.Constructor:
    case SyntaxKind.GetAccessor:
    case SyntaxKind.SetAccessor:
    case SyntaxKind.FunctionType:
    case SyntaxKind.ConstructorType:
    case SyntaxKind.FunctionExpression:
    case SyntaxKind.ArrowFunction:
    case SyntaxKind.ModuleDeclaration:
    case SyntaxKind.SourceFile:
    case SyntaxKind.TypeAliasDeclaration:
      return ContainerFlags.IsContainerWithLocals;

    case SyntaxKind.CatchClause:
    case SyntaxKind.ForStatement:
    case SyntaxKind.ForInStatement:
    case SyntaxKind.ForOfStatement:
    case SyntaxKind.CaseBlock:
      return ContainerFlags.IsBlockScopedContainer;

    case SyntaxKind.Block:
      // 不要将函数内部的块直接当做块作用域的容器。
      // 本块中的本地变量应当置于函数中,否则下例中的 'x' 不会重新声明为一个块作用域的本地变量:
      //
      //     function foo() {
      //         var x;
      //         let x;
      //     }
      //
      // 如果将 'var x' 留在函数中,而将 'let x' 放到本块中(函数外),就不会有冲突了。
      //
      // 如果不在这里创建一个新的块作用域容器,'var x' 和 'let x' 都会进入函数容器本地中,这样就会有碰撞冲突。
      return isFunctionLike(node.parent) ? ContainerFlags.None : ContainerFlags.IsBlockScopedContainer;
  }

  return ContainerFlags.None;
}
```

该函数*只*在绑定器函数 `bindChildren` 中调用,会根据 `getContainerFlags` 的运行结果将节点设为 `container` 和(或) `blockScopedContainer`。函数 `bindChildren` 如下所示:

```ts
// 所有容器节点都以声明顺序保存在一个链表中。
// 类型检查器中的 getLocalNameOfContainer 函数会使用该链表对容器使用的本地名称的唯一性做验证。
function bindChildren(node: Node) {
  // 在递归到子节点之前,我们先要保存父节点,容器和块容器。处理完弹出的子节点后,再将这些值存回原处。
  let saveParent = parent;
  let saveContainer = container;
  let savedBlockScopeContainer = blockScopeContainer;

  // 现在要将这个节点设为父节点,我们要递归它的子节点。
  parent = node;

  // 根据节点的类型,需要对当前容器或块容器进行调整。 如果当前节点是个容器,则自动将其视为当前的块容器。
  // 由于我们知道容器可能包含本地变量,因此提前初始化 .locals 字段。
  // 这样做是因为很可能需要将一些子(节点)置入 .locals 中(例如:函数参数或变量声明)。
  //
  // 但是,我们不会主动为块容器创建 .locals,因为通常块容器中不会有块作用域变量。
  // 我们不想为遇到的每个块都分配一个对象,大多数情况没有必要。
  //
  // 最后,如果是个块容器,我们就清理该容器中可能存在的 .locals 对象。这种情况常在增量编译场景中发生。
  // 由于我们可以重用上次编译的节点,而该节点可能已经创建了 locals 对象。
  // 因此必须清理,以免意外地从上次的编译中移动了过时的数据。
  let containerFlags = getContainerFlags(node);
  if (containerFlags & ContainerFlags.IsContainer) {
    container = blockScopeContainer = node;

    if (containerFlags & ContainerFlags.HasLocals) {
      container.locals = {};
    }

    addToContainerChain(container);
  } else if (containerFlags & ContainerFlags.IsBlockScopedContainer) {
    blockScopeContainer = node;
    blockScopeContainer.locals = undefined;
  }

  forEachChild(node, bind);

  container = saveContainer;
  parent = saveParent;
  blockScopeContainer = savedBlockScopeContainer;
}
```

您可能还记得绑定器函数中的这部分:`bindChildren` 由 `bind` 函数调用。我们得到这样的递归绑定:`bind` 调用 `bindChildren`,而 `bindChildren` 又为其每个子节点调用 `bind`

## 绑定器符号表

符号表(SymbolTable)是以一个简单的 HashMap 实现的,下面是其接口(`types.ts`):

```ts
interface SymbolTable {
  [index: string]: Symbol;
}
```

符号表通过绑定进行初始化,这里是编译器使用的一些符号表:

节点上:

```ts
locals?: SymbolTable;                   // 节点相关的本地变量
```

符号上:

```ts
members?: SymbolTable;                  // 类,接口或字面量实例成员
exports?: SymbolTable;                  // 模块导出
```

请注意:`bindChildren` 基于 `ContainerFlags` 初始化 `locals`(为 `{}`)

### 符号表填充

符号表使用符号来填充,主要是通过调用 `declareSymbol` 来进行,如下所示的是该函数的全部代码:

```ts
/**
 * 为指定的节点声明一个符号并加入 symbols。标识名冲突时报告错误。
 * @param symbolTable - 要将节点加入进的符号表
 * @param parent - 指定节点的父节点的声明
 * @param node - 要添加到符号表的(节点)声明
 * @param includes - SymbolFlags,指定节点额外的声明类型(例如:export, ambient 等)
 * @param excludes - 不能在符号表中声明的标志,用于报告禁止的声明
 */
function declareSymbol(
  symbolTable: SymbolTable,
  parent: Symbol,
  node: Declaration,
  includes: SymbolFlags,
  excludes: SymbolFlags
): Symbol {
  Debug.assert(!hasDynamicName(node));

  // 默认导出的函数节点或类节点的符号总是"default"
  let name = node.flags & NodeFlags.Default && parent ? 'default' : getDeclarationName(node);

  let symbol: Symbol;
  if (name !== undefined) {
    // 检查符号表中是否已有同名的符号。若没有,创建此名称的新符号并加入表中。
    // 注意,我们尚未给新符号指定任何标志。这可以确保不会和传入的 excludes 标志起冲突。
    //
    // 如果已存在的一个符号,查看是否与要创建的新符号冲突。
    // 例如:同一符号表中,'var' 符号和 'class' 符号会冲突。
    // 如果有冲突,报告该问题给该符号的每个声明,然后为该声明创建一个新符号
    //
    // 如果我们创建的新符号既没在符号表中重名也没和现有符号冲突,就将该节点添加为新符号的唯一声明。
    //
    // 否则,就要(将新符号)合并进兼容的现有符号中(例如同一容器中有多个同名的 'var' 时)。这种情况下要把该节点添加到符号的声明列表中。
    symbol = hasProperty(symbolTable, name)
      ? symbolTable[name]
      : (symbolTable[name] = createSymbol(SymbolFlags.None, name));

    if (name && includes & SymbolFlags.Classifiable) {
      classifiableNames[name] = name;
    }

    if (symbol.flags & excludes) {
      if (node.name) {
        node.name.parent = node;
      }

      // 报告每个重复声明的错误位置
      // 报告之前遇到的声明错误
      let message =
        symbol.flags & SymbolFlags.BlockScopedVariable
          ? Diagnostics.Cannot_redeclare_block_scoped_variable_0
          : Diagnostics.Duplicate_identifier_0;
      forEach(symbol.declarations, declaration => {
        file.bindDiagnostics.push(
          createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration))
        );
      });
      file.bindDiagnostics.push(createDiagnosticForNode(node.name || node, message, getDisplayName(node)));

      symbol = createSymbol(SymbolFlags.None, name);
    }
  } else {
    symbol = createSymbol(SymbolFlags.None, '__missing');
  }

  addDeclarationToSymbol(symbol, node, includes);
  symbol.parent = parent;

  return symbol;
}
```

填充哪个符号表,由此函数的第一个参数决定。例如:添加声明到类型为 `SyntaxKind.ClassDeclaration` 或 `SyntaxKind.ClassExpression` 的*容器*时,将会调用下面的函数 `declareClassMember`:

```ts
function declareClassMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
  return node.flags & NodeFlags.Static
    ? declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes)
    : declareSymbol(container.symbol.members, container.symbol, node, symbolFlags, symbolExcludes);
}
```

## 绑定器错误报告

绑定错误被添加到源文件的 `bindDiagnostics` 列表中

一个绑定时错误检测的例子是在严格模式下使用 `eval` 或 `arguments` 作为变量名。下面展示了相关的全部代码(多个位置都会调用`checkStrictModeEvalOrArguments`,调用栈发自 `bindWorker`,该函数对不同节点的 `SyntaxKind` 调用不同的检查函数):

```ts
function checkStrictModeEvalOrArguments(contextNode: Node, name: Node) {
  if (name && name.kind === SyntaxKind.Identifier) {
    let identifier = <Identifier>name;
    if (isEvalOrArgumentsIdentifier(identifier)) {
      // 首先检查名字是否在类声明或者类表达式中,如果是则给出明确消息,否则报告一般性错误
      let span = getErrorSpanForNode(file, name);
      file.bindDiagnostics.push(
        createFileDiagnostic(
          file,
          span.start,
          span.length,
          getStrictModeEvalOrArgumentsMessage(contextNode),
          identifier.text
        )
      );
    }
  }
}

function isEvalOrArgumentsIdentifier(node: Node): boolean {
  return (
    node.kind === SyntaxKind.Identifier &&
    ((<Identifier>node).text === 'eval' || (<Identifier>node).text === 'arguments')
  );
}

function getStrictModeEvalOrArgumentsMessage(node: Node) {
  // 向用户提供特定消息,有助他们理解为何会处于严格模式。
  if (getContainingClass(node)) {
    return Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode;
  }

  if (file.externalModuleIndicator) {
    return Diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode;
  }

  return Diagnostics.Invalid_use_of_0_in_strict_mode;
}
```


================================================
FILE: docs/compiler/checker.md
================================================
# 检查器

如前所述,*检查器*使得 TypeScript 更独特,比*其它 JavaScript 转译器*更强大。检查器位于 `checker.ts` 中,当前有 23k 行以上的代码(编译器中最大的部分)

### 程序对检查器的使用

检查器是由程序初始化,下面是调用栈示意(绑定器一节也展示过):

```
program.getTypeChecker ->
    ts.createTypeChecker(检查器中)->
        initializeTypeChecker(检查器中) ->
            for each SourceFile `ts.bindSourceFile`(绑定器中)
            // 接着
            for each SourceFile `ts.mergeSymbolTable`(检查器中)
```

### 与发射器的联系

真正的类型检查会在调用 `getDiagnostics` 时才发生。该函数被调用时(比如由 `Program.emit` 请求),检查器返回一个 `EmitResolver`(由程序调用检查器的 `getEmitResolver` 函数得到),`EmitResolver` 是 `createTypeChecker` 的一个本地函数的集合。介绍发射器时还会再次提到。

下面是该过程直到 `checkSourceFile` 的调用栈(`checkSourceFile` 是 `createTypeChecker` 的一个本地函数):

```
program.emit ->
    emitWorker (program local) ->
        createTypeChecker.getEmitResolver ->
            // 第一次调用下面的几个 createTypeChecker 的本地函数
            call getDiagnostics ->
                getDiagnosticsWorker ->
                    checkSourceFile

            // 接着
            return resolver
            // 通过对本地函数 createResolver() 的调用,resolver 已在 createTypeChecker 中初始化。
```

## 全局命名空间合并

`initializeTypeChecker` 中存在以下代码:

```ts
// 初始化全局符号表(SymbolTable)。
forEach(host.getSourceFiles(), file => {
  if (!isExternalModule(file)) {
    mergeSymbolTable(globals, file.locals);
  }
});
```

基本上是将所有的 `global` 符号合并到 `let globals: SymbolTable = {}` 符号表中(位于 `createTypeChecker` 中)。
`mergeSymbolTable` 主要调用 `mergeSymbol` 函数。

## 检查器错误报告

检查器使用本地的 `error` 函数报告错误,如下所示:

```ts
function error(location: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
  let diagnostic = location
    ? createDiagnosticForNode(location, message, arg0, arg1, arg2)
    : createCompilerDiagnostic(message, arg0, arg1, arg2);
  diagnostics.add(diagnostic);
}
```


================================================
FILE: docs/compiler/emitter.md
================================================
# 发射器

TypeScript 编译器提供了两个发射器:

- `emitter.ts`:可能是你最感兴趣的发射器,它是 TS -> JavaScript 的发射器
- `declarationEmitter.ts`:这个发射器用于为 _TypeScript 源文件(`.ts`)_ 创建*声明文件(`.d.ts`)*

本节我们介绍 `emitter.ts`

### Promgram 对发射器的使用

Program 提供了一个 `emit` 函数。该函数主要将功能委托给 `emitter.ts`中的 `emitFiles` 函数。下面是调用栈:

```
Program.emit ->
    `emitWorker` (在 program.ts 中的 createProgram) ->
        `emitFiles` (emitter.ts 中的函数)
```

`emitWorker`(通过 `emitFiles` 参数)给发射器提供一个 `EmitResolver`。 `EmitResolver` 由程序的 TypeChecker 提供,基本上它是一个来自 `createChecker` 的本地函数的子集。

## 发射器函数

### `emitFiles`

定义在 `emitter.ts` 中,下面是该函数的签名:

```ts
// targetSourceFile 当用户想发射项目中的某个文件时指定,保存时编译(compileOnSave)功能使用此参数
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile?: SourceFile): EmitResult {
```

`EmitHost` 是 `CompilerHost` 的简化版(运行时,很多用例实际上都是 `CompilerHost`)

`emitFiles` 中的最有趣的调用栈如下所示:

```
emitFiles ->
    emitFile(jsFilePath, targetSourceFile) ->
        emitJavaScript(jsFilePath, targetSourceFile);
```

### `emitJavaScript`

该函数有良好的注释,我们下面给出它:

```ts
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
  let writer = createTextWriter(newLine);
  let write = writer.write;
  let writeTextOfNode = writer.writeTextOfNode;
  let writeLine = writer.writeLine;
  let increaseIndent = writer.increaseIndent;
  let decreaseIndent = writer.decreaseIndent;

  let currentSourceFile: SourceFile;
  // 导出器函数的名称,如果文件是个系统外部模块的话
  // System.register([...], function (<exporter>) {...})
  // System 模块中的导出像这样:
  // export var x; ... x = 1
  // =>
  // var x;... exporter("x", x = 1)
  let exportFunctionForFile: string;

  let generatedNameSet: Map<string> = {};
  let nodeToGeneratedName: string[] = [];
  let computedPropertyNamesToGeneratedNames: string[];

  let extendsEmitted = false;
  let decorateEmitted = false;
  let paramEmitted = false;
  let awaiterEmitted = false;
  let tempFlags = 0;
  let tempVariables: Identifier[];
  let tempParameters: Identifier[];
  let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[];
  let exportSpecifiers: Map<ExportSpecifier[]>;
  let exportEquals: ExportAssignment;
  let hasExportStars: boolean;

  /** 将发射输出写入磁盘 */
  let writeEmittedFiles = writeJavaScriptFile;

  let detachedCommentsInfo: { nodePos: number; detachedCommentEndPos: number }[];

  let writeComment = writeCommentRange;

  /** 发射一个节点 */
  let emit = emitNodeWithoutSourceMap;

  /** 在发射节点前调用 */
  let emitStart = function(node: Node) {};

  /** 发射结点完成后调用 */
  let emitEnd = function(node: Node) {};

  /** 从 startPos 位置开始,为指定的 token 发射文本。默认写入的文本由 tokenKind 提供,
   * 但是如果提供了可选的 emitFn 回调,将使用该回调来代替默认方式发射文本。
   * @param tokenKind 要搜索并发射的 token 的类别
   * @param startPos 源码中搜索 token 的起始位置
   * @param emitFn 如果给出,会被调用来进行文本的发射。
   */
  let emitToken = emitTokenText;

  /** 该函数由于节点的缘故,在被发射的代码中的函数或类中,会在启用词法作用域前被调用
   * @param scopeDeclaration 启动词法作用域的节点
   * @param scopeName 可选的作用域的名称,默认从节点声明中推导
   */
  let scopeEmitStart = function(scopeDeclaration: Node, scopeName?: string) {};

  /** 出了作用域后调用 */
  let scopeEmitEnd = function() {};

  /** 会被编码的 Sourcemap 数据 */
  let sourceMapData: SourceMapData;

  if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
    initializeEmitterWithSourceMaps();
  }

  if (root) {
    // 不要直接调用 emit,那样不会设置 currentSourceFile
    emitSourceFile(root);
  } else {
    forEach(host.getSourceFiles(), sourceFile => {
      if (!isExternalModuleOrDeclarationFile(sourceFile)) {
        emitSourceFile(sourceFile);
      }
    });
  }

  writeLine();
  writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM);
  return;

  /// 一批本地函数
}
```

它主要设置了一批本地变量和函数(这些函数构成 `emitter.ts` 的*大部分*内容),接着交给本地函数 `emitSourceFile` 发射文本。`emitSourceFile` 函数设置 `currentSourceFile` 然后交给本地函数 `emit` 去处理。

```ts
function emitSourceFile(sourceFile: SourceFile): void {
  currentSourceFile = sourceFile;
  exportFunctionForFile = undefined;
  emit(sourceFile);
}
```

`emit` 函数处理 _注释_ 和 _实际 JavaScript_ 的发射。_实际 JavaScript_ 的发射是 emitJavaScriptWorker 函数的工作。

### `emitJavaScriptWorker`

完整的函数:

```ts
function emitJavaScriptWorker(node: Node) {
  // 检查节点是否可以忽略 ScriptTarget 发射
  switch (node.kind) {
    case SyntaxKind.Identifier:
      return emitIdentifier(<Identifier>node);
    case SyntaxKind.Parameter:
      return emitParameter(<ParameterDeclaration>node);
    case SyntaxKind.MethodDeclaration:
    case SyntaxKind.MethodSignature:
      return emitMethod(<MethodDeclaration>node);
    case SyntaxKind.GetAccessor:
    case SyntaxKind.SetAccessor:
      return emitAccessor(<AccessorDeclaration>node);
    case SyntaxKind.ThisKeyword:
      return emitThis(node);
    case SyntaxKind.SuperKeyword:
      return emitSuper(node);
    case SyntaxKind.NullKeyword:
      return write('null');
    case SyntaxKind.TrueKeyword:
      return write('true');
    case SyntaxKind.FalseKeyword:
      return write('false');
    case SyntaxKind.NumericLiteral:
    case SyntaxKind.StringLiteral:
    case SyntaxKind.RegularExpressionLiteral:
    case SyntaxKind.NoSubstitutionTemplateLiteral:
    case SyntaxKind.TemplateHead:
    case SyntaxKind.TemplateMiddle:
    case SyntaxKind.TemplateTail:
      return emitLiteral(<LiteralExpression>node);
    case SyntaxKind.TemplateExpression:
      return emitTemplateExpression(<TemplateExpression>node);
    case SyntaxKind.TemplateSpan:
      return emitTemplateSpan(<TemplateSpan>node);
    case SyntaxKind.JsxElement:
    case SyntaxKind.JsxSelfClosingElement:
      return emitJsxElement(<JsxElement | JsxSelfClosingElement>node);
    case SyntaxKind.JsxText:
      return emitJsxText(<JsxText>node);
    case SyntaxKind.JsxExpression:
      return emitJsxExpression(<JsxExpression>node);
    case SyntaxKind.QualifiedName:
      return emitQualifiedName(<QualifiedName>node);
    case SyntaxKind.ObjectBindingPattern:
      return emitObjectBindingPattern(<BindingPattern>node);
    case SyntaxKind.ArrayBindingPattern:
      return emitArrayBindingPattern(<BindingPattern>node);
    case SyntaxKind.BindingElement:
      return emitBindingElement(<BindingElement>node);
    case SyntaxKind.ArrayLiteralExpression:
      return emitArrayLiteral(<ArrayLiteralExpression>node);
    case SyntaxKind.ObjectLiteralExpression:
      return emitObjectLiteral(<ObjectLiteralExpression>node);
    case SyntaxKind.PropertyAssignment:
      return emitPropertyAssignment(<PropertyDeclaration>node);
    case SyntaxKind.ShorthandPropertyAssignment:
      return emitShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
    case SyntaxKind.ComputedPropertyName:
      return emitComputedPropertyName(<ComputedPropertyName>node);
    case SyntaxKind.PropertyAccessExpression:
      return emitPropertyAccess(<PropertyAccessExpression>node);
    case SyntaxKind.ElementAccessExpression:
      return emitIndexedAccess(<ElementAccessExpression>node);
    case SyntaxKind.CallExpression:
      return emitCallExpression(<CallExpression>node);
    case SyntaxKind.NewExpression:
      return emitNewExpression(<NewExpression>node);
    case SyntaxKind.TaggedTemplateExpression:
      return emitTaggedTemplateExpression(<TaggedTemplateExpression>node);
    case SyntaxKind.TypeAssertionExpression:
      return emit((<TypeAssertion>node).expression);
    case SyntaxKind.AsExpression:
      return emit((<AsExpression>node).expression);
    case SyntaxKind.ParenthesizedExpression:
      return emitParenExpression(<ParenthesizedExpression>node);
    case SyntaxKind.FunctionDeclaration:
    case SyntaxKind.FunctionExpression:
    case SyntaxKind.ArrowFunction:
      return emitFunctionDeclaration(<FunctionLikeDeclaration>node);
    case SyntaxKind.DeleteExpression:
      return emitDeleteExpression(<DeleteExpression>node);
    case SyntaxKind.TypeOfExpression:
      return emitTypeOfExpression(<TypeOfExpression>node);
    case SyntaxKind.VoidExpression:
      return emitVoidExpression(<VoidExpression>node);
    case SyntaxKind.AwaitExpression:
      return emitAwaitExpression(<AwaitExpression>node);
    case SyntaxKind.PrefixUnaryExpression:
      return emitPrefixUnaryExpression(<PrefixUnaryExpression>node);
    case SyntaxKind.PostfixUnaryExpression:
      return emitPostfixUnaryExpression(<PostfixUnaryExpression>node);
    case SyntaxKind.BinaryExpression:
      return emitBinaryExpression(<BinaryExpression>node);
    case SyntaxKind.ConditionalExpression:
      return emitConditionalExpression(<ConditionalExpression>node);
    case SyntaxKind.SpreadElementExpression:
      return emitSpreadElementExpression(<SpreadElementExpression>node);
    case SyntaxKind.YieldExpression:
      return emitYieldExpression(<YieldExpression>node);
    case SyntaxKind.OmittedExpression:
      return;
    case SyntaxKind.Block:
    case SyntaxKind.ModuleBlock:
      return emitBlock(<Block>node);
    case SyntaxKind.VariableStatement:
      return emitVariableStatement(<VariableStatement>node);
    case SyntaxKind.EmptyStatement:
      return write(';');
    case SyntaxKind.ExpressionStatement:
      return emitExpressionStatement(<ExpressionStatement>node);
    case SyntaxKind.IfStatement:
      return emitIfStatement(<IfStatement>node);
    case SyntaxKind.DoStatement:
      return emitDoStatement(<DoStatement>node);
    case SyntaxKind.WhileStatement:
      return emitWhileStatement(<WhileStatement>node);
    case SyntaxKind.ForStatement:
      return emitForStatement(<ForStatement>node);
    case SyntaxKind.ForOfStatement:
    case SyntaxKind.ForInStatement:
      return emitForInOrForOfStatement(<ForInStatement>node);
    case SyntaxKind.ContinueStatement:
    case SyntaxKind.BreakStatement:
      return emitBreakOrContinueStatement(<BreakOrContinueStatement>node);
    case SyntaxKind.ReturnStatement:
      return emitReturnStatement(<ReturnStatement>node);
    case SyntaxKind.WithStatement:
      return emitWithStatement(<WithStatement>node);
    case SyntaxKind.SwitchStatement:
      return emitSwitchStatement(<SwitchStatement>node);
    case SyntaxKind.CaseClause:
    case SyntaxKind.DefaultClause:
      return emitCaseOrDefaultClause(<CaseOrDefaultClause>node);
    case SyntaxKind.LabeledStatement:
      return emitLabelledStatement(<LabeledStatement>node);
    case SyntaxKind.ThrowStatement:
      return emitThrowStatement(<ThrowStatement>node);
    case SyntaxKind.TryStatement:
      return emitTryStatement(<TryStatement>node);
    case SyntaxKind.CatchClause:
      return emitCatchClause(<CatchClause>node);
    case SyntaxKind.DebuggerStatement:
      return emitDebuggerStatement(node);
    case SyntaxKind.VariableDeclaration:
      return emitVariableDeclaration(<VariableDeclaration>node);
    case SyntaxKind.ClassExpression:
      return emitClassExpression(<ClassExpression>node);
    case SyntaxKind.ClassDeclaration:
      return emitClassDeclaration(<ClassDeclaration>node);
    case SyntaxKind.InterfaceDeclaration:
      return emitInterfaceDeclaration(<InterfaceDeclaration>node);
    case SyntaxKind.EnumDeclaration:
      return emitEnumDeclaration(<EnumDeclaration>node);
    case SyntaxKind.EnumMember:
      return emitEnumMember(<EnumMember>node);
    case SyntaxKind.ModuleDeclaration:
      return emitModuleDeclaration(<ModuleDeclaration>node);
    case SyntaxKind.ImportDeclaration:
      return emitImportDeclaration(<ImportDeclaration>node);
    case SyntaxKind.ImportEqualsDeclaration:
      return emitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
    case SyntaxKind.ExportDeclaration:
      return emitExportDeclaration(<ExportDeclaration>node);
    case SyntaxKind.ExportAssignment:
      return emitExportAssignment(<ExportAssignment>node);
    case SyntaxKind.SourceFile:
      return emitSourceFileNode(<SourceFile>node);
  }
}
```

通过简单地调用相应的 `emitXXX` 函数来完成递归,例如 `emitFunctionDeclaration`

```ts
function emitFunctionDeclaration(node: FunctionLikeDeclaration) {
  if (nodeIsMissing(node.body)) {
    return emitOnlyPinnedOrTripleSlashComments(node);
  }

  if (node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.MethodSignature) {
    // 会把注释当做方法声明的一部分去发射。
    emitLeadingComments(node);
  }

  // 目标为 es6 之前时,使用 function 关键字来发射类函数(functions-like)声明,包括箭头函数
  // 目标为 es6 时,可以发射原生的 ES6 箭头函数,并使用宽箭头代替 function 关键字.
  if (!shouldEmitAsArrowFunction(node)) {
    if (isES6ExportedDeclaration(node)) {
      write('export ');
      if (node.flags & NodeFlags.Default) {
        write('default ');
      }
    }

    write('function');
    if (languageVersion >= ScriptTarget.ES6 && node.asteriskToken) {
      write('*');
    }
    write(' ');
  }

  if (shouldEmitFunctionName(node)) {
    emitDeclarationName(node);
  }

  emitSignatureAndBody(node);
  if (
    languageVersion < ScriptTarget.ES6 &&
    node.kind === SyntaxKind.FunctionDeclaration &&
    node.parent === currentSourceFile &&
    node.name
  ) {
    emitExportMemberAssignments((<FunctionDeclaration>node).name);
  }
  if (node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.MethodSignature) {
    emitTrailingComments(node);
  }
}
```

## 发射器源映射(SourceMaps)

如前所述 `emitter.ts` 中的大部分代码是函数 `emitJavaScript`(我们之前展示过该函数的初始化例程)。
它主要是设置一批本地变量并交给 `emitSourceFile` 处理。下面我们再看一遍这个函数,这次我们重点关注 `SourceMap` 的部分:

```ts
function emitJavaScript(jsFilePath: string, root?: SourceFile) {

    // 无关代码 ........... 已移除
    let writeComment = writeCommentRange;

    /** 将发射的输出写到磁盘上 */
    let writeEmittedFiles = writeJavaScriptFile;

    /** 发射一个节点 */
    let emit = emitNodeWithoutSourceMap;

    /** 节点发射前调用 */
    let emitStart = function (node: Node) { };

    /** 节点发射完成后调用 */
    let emitEnd = function (node: Node) { };

    /** 从 startPos 位置开始,为指定的 token 发射文本。默认写入的文本由 tokenKind 提供,
      * 但是如果提供了可选的 emitFn 回调,将使用该回调来代替默认方式发射文本。
      * @param tokenKind 要搜索并发射的 token 的类别
      * @param startPos 源码中搜索 token 的起始位置
      * @param emitFn 如果给出,会被调用来进行文本的发射。*/
    let emitToken = emitTokenText;

    /** 该函数因为节点,会在发射的代码中于函数或类中启用词法作用域前调用
      * @param scopeDeclaration 启动词法作用域的节点
      * @param scopeName 可选的作用域的名称,而不是从节点声明中推导
      */
    let scopeEmitStart = function(scopeDeclaration: Node, scopeName?: string) { };

    /** 出了作用域后调用 */
    let scopeEmitEnd = function() { };

    /** 会被编码的 Sourcemap 数据 */
    let sourceMapData: SourceMapData;

    if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
        initializeEmitterWithSourceMaps();
    }

    if (root) {
        // 不要直接调用 emit,那样不会设置 currentSourceFile
        emitSourceFile(root);
    }
    else {
        forEach(host.getSourceFiles(), sourceFile => {
            if (!isExternalModuleOrDeclarationFile(sourceFile)) {
                emitSourceFile(sourceFile);
            }
        });
    }

    writeLine();
    writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM);
    return;
```

重要的函数调用: `initializeEmitterWithSourceMaps`,该函数是 `emitJavaScript` 的本地函数,它覆盖了部分已定义的本地函数。
覆盖的函数可以在 `initalizeEmitterWithSourceMap` 的底部找到:

```ts
// `initializeEmitterWithSourceMaps` 函数的最后部分

writeEmittedFiles = writeJavaScriptAndSourceMapFile;
emit = emitNodeWithSourceMap;
emitStart = recordEmitNodeStartSpan;
emitEnd = recordEmitNodeEndSpan;
emitToken = writeTextWithSpanRecord;
scopeEmitStart = recordScopeNameOfNode;
scopeEmitEnd = recordScopeNameEnd;
writeComment = writeCommentRangeWithMap;
```

就是说大部分的发射器代码不关心 `SourceMap`,它们以相同的方式使用这些(带或不带 SourceMap 的)本地函数。


================================================
FILE: docs/compiler/overview.md
================================================
# 概览

TypeScript 编译器源文件位于 [`src/compiler`](https://github.com/Microsoft/TypeScript/tree/master/src/compiler) 目录下

> 译注:Typescript Deep Dive 使用的源码应为 2016 年以前的源码。学习时请对照现有的源码

它分为以下几个关键部分:

- Scanner 扫描器(`scanner.ts`)
- Parser 解析器(`parser.ts`)
- Binder 绑定器(`binder.ts`)
- Checker 检查器(`checker.ts`)
- Emitter 发射器(`emitter.ts`)

每个部分在源文件中均有独立文件,本章稍后会对这些部分做解释。

### BYOTS

我们有个名为 [Bring Your Own TypeScript (BYOTS)](https://github.com/basarat/byots) 的项目,通过暴露内部接口让编译器 API 使用起来更简单。你可以在全局范围上暴露你 TypeScript 应用的本地变量。

### 语法和语义

*语法*正确并不意味着*语义*上也正确。下面的 TypeScript 代码,语法合法,但是语义却不正确

```ts
var foo: number = 'not a number';
```

`语义` 从自然语言角度意味着有意义,理解这个概念对你很有用。

### 处理概览

以下演示简单说明 TypeScript 编译器如何将上述几个关键部分组合在一起:

```code
SourceCode(源码) ~~ 扫描器 ~~> Token 流
```

```code
Token 流 ~~ 解析器 ~~> AST(抽象语法树)
```

```code
AST ~~ 绑定器 ~~> Symbols(符号)
```

符号(`Symbol`)是 TypeScript *语义*系统的主要构造块。如上所示,符号是绑定的结果。符号将 AST 中的声明节点与相同实体的其他声明相连。

符号和 AST 是检查器用来验证源代码*语义*的

```code
AST + 符号 ~~ 检查器 ~~> 类型验证
```

最后,需要输出 JavaScript 时:

```code
AST + 检查器 ~~ 发射器 ~~> JavaScript 代码
```

TypeScript 编译器中还有一些其他文件,为我们接下来介绍的很多关键部分提供实用工具。

## 文件:Utilities

`core.ts` :TypeScript 编译器使用的核心工具集,重要的有:

- `let objectAllocator: ObjectAllocator` 是一个定义为全局单例的变量。提供以下定义:
  - `getNodeConstructor`(节点会在解析器 / AST 中介绍)
  - `getSymbolConstructor`(符号会在绑定器中介绍)
  - `getTypeConstructor`(类型会在检查器中介绍)
  - `getSignatureConstructor`(签名是索引,调用和构造签名)

## 文件:关键数据结构

`types.ts` 包含整个编译器中使用的关键数据结构和接口,这里列出一些关键部分:

- `SyntaxKind`
  AST 节点类型通过 `SyntaxKind` 枚举进行识别
- `TypeChecker`
  类型检查器提供此接口
- `CompilerHost`
  用于程序(`Program`)和系统之间的交互
- `Node`
  AST 节点

## 文件:系统

`system.ts`,TypeScript 编译器与操作系统的所有交互均通过 `System` 接口进行。接口及其实现(`WScript` 和 `Node`) 均定义在 `system.ts` 中。你可以将其视为*操作环境(OE, Operating Environment)*。

现在对主要文件有一个整体了解了,我们继续介绍程序([`Program`](./program.md))的概念


================================================
FILE: docs/compiler/parser.md
================================================
# 解析器

TypeScript 解析器代码均位于 `parser.ts` 中。在内部,由解析器控制扫描器将源码转化为 AST。其期望结果如下:

```
源码 ~~ 扫描器 ~~> Token 流 ~~ 解析器 ~~> AST
```

解析器实现原理是单例模式(其原因类似扫描器,如果能重新初始化就不重新构建)。实际实现成 `namespace Parser`,包含解析器的各种*状态*变量和单例扫描器(`const scanner`)。该扫描器由解析器函数管理。

### 程序对解析器的使用

解析器由程序间接驱动(通过之前提到过的 `CompilerHost`)。基本上,简化的调用栈如下所示:

```
程序 ->
    CompilerHost.getSourceFile ->
        (全局函数 parser.ts).createSourceFile ->
            Parser.parseSourceFile
```

`parseSourceFile` 不仅准备好解析器的状态,还调用 `initializeState` 准备好扫描器的状态。然后使用 `parseSourceFileWorker` 继续解析源代码。

### 使用示例

深入解析器的内部之前,这里有个使用 TypeScript 解析器的示例,(使用 `ts.createSourceFile`)获取一个源文件的 AST 并打印它。

`code/compiler/parser/runParser.ts`

```ts
import * as ts from 'ntypescript';

function printAllChildren(node: ts.Node, depth = 0) {
  console.log(new Array(depth + 1).join('----'), ts.formatSyntaxKind(node.kind), node.pos, node.end);
  depth++;
  node.getChildren().forEach(c => printAllChildren(c, depth));
}

var sourceCode = `
var foo = 123;
`.trim();

var sourceFile = ts.createSourceFile('foo.ts', sourceCode, ts.ScriptTarget.ES5, true);
printAllChildren(sourceFile);
```

该段代码会打印以下内容:

```ts
SourceFile 0 14
---- SyntaxList 0 14
-------- VariableStatement 0 14
------------ VariableDeclarationList 0 13
---------------- VarKeyword 0 3
---------------- SyntaxList 3 13
-------------------- VariableDeclaration 3 13
------------------------ Identifier 3 7
------------------------ FirstAssignment 7 9
------------------------ FirstLiteralToken 9 13
------------ SemicolonToken 13 14
---- EndOfFileToken 14 14
```

如果把头向左倾,这个看起来像棵(右侧)树

## 解析器函数

如前所述,`parseSourceFile` 设置初始状态并将工作交给 `parseSourceFileWorker` 函数。

### `parseSourceFileWorker`

该函数先创建一个 `SourceFile` AST 节点,然后从 `parseStatements` 函数开始解析源代码。一旦返回结果,就用额外信息(例如 `nodeCount`, `identifierCount`等) 完善 `SourceFile` 节点。

### `parseStatements`

是最重要的 `parseXXX` 系函数之一(概念接下来介绍)。它根据扫描器返回的当前 token 来切换(调用相应的 `parseXXX` 函数),例如:如果当前 token 是一个 `SemicolonToken`(分号标记),就会调用 `paserEmptyStatement` 为空语句创建一个 AST 节点。

### 节点创建

解析器有一系列 `parseXXX` 函数用来创建相应类型为`XXX`的节点,通常在相应类型的节点出现时被(其他解析器函数)调用。该过程的典型示例是解析空语句(例如 `;;;;;;`)时要用的 `parseEmptyStatement()` 函数。下面是其全部代码:

```ts
function parseEmptyStatement(): Statement {
  let node = <Statement>createNode(SyntaxKind.EmptyStatement);
  parseExpected(SyntaxKind.SemicolonToken);
  return finishNode(node);
}
```

它展示了 3 个关键函数 `createNode`, `parseExpected` 和 `finishNode`.

#### `createNode`

解析器函数 `function createNode(kind: SyntaxKind, pos?: number): Node` 负责创建节点,设置传入的 `SyntaxKind`(语法类别),和初始位置(默认使用当前扫描器状态提供的位置信息)。

#### `parseExpected`

解析器的 `parseExpected` 函数 `function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage): boolean` 会检查解析器状态中的当前 token 是否与指定的 `SyntaxKind` 匹配。如果不匹配,则会向传入的 `diagnosticMessage`(诊断消息)报告,未传入则创建某种通用形式 `xxx expected`。该函数内部用 `parseErrorAtPosition` 函数(使用扫描位置)提供良好的错误报告。

#### `finishNode`

解析器的 `finishNode` 函数 `function finishNode<T extends Node>(node: T, end?: number): T` 设置节点的 `end` 位置,并添加一些有用的信息,例如上下文标志(`parserContextFlags`)以及解析该节点前出现的错误(如果有错的话,就不能在增量解析中重用此 AST 节点)。


================================================
FILE: docs/compiler/program.md
================================================
# 程序

程序定义在 `program.ts` 中。[编译上下文](../project/compilationContext.md)在 TypeScript 编译器中被视为一个 `Program`,它包含 `SourceFile` 和编译选项

## `CompilerHost` 的使用

CompilerHost 是与操作环境(OE, Operating Enviornment)进行交互的机制:

`Program` _-使用->_ `CompilerHost` _-使用->_ `System`

用 `CompilerHost` 作中间层的原因是可以让接口对 `Program` 的需求进行细粒度的调整,而无需考虑操作环境的需求。(例如:`Program` 无需关心 `System` 的 `fileExists` 函数)

对`System`而言还有其他的使用者(比如测试)

## SourceFile

程序有个 API,用于获取 SourceFile:`getSourceFiles(): SourceFile[];`。得到的每个元素均是一棵抽象语法树的根节点(称做 `SourceFile`)


================================================
FILE: docs/compiler/scanner.md
================================================
# 扫描器

TypeScript 扫描器的源码均位于 `scanner.ts`。在内部,由解析器*控制*扫描器将源码转化为抽象语法树(AST)。期望结果如下:

```
SourceCode ~~ 扫描器 ~~> Token 流 ~~ 解析器 ~~> AST
```

## 解析器对扫描器的使用

为避免重复创建扫描器造成的开销,`parser.ts` 中创建了一个扫描器的*单例*。解析器根据需要使用 `initializeState` 函数*准备*该扫描器。

下面是解析器中的实际代码的简化版,你可以运行它演示以上概念

`code/compiler/scanner/runScanner.ts`

```ts
import * as ts from 'ntypescript';

// 单例扫描器
const scanner = ts.createScanner(ts.ScriptTarget.Latest, /* 忽略杂项 */ true);

// 此函数与初始化使用的 `initializeState` 函数相似
function initializeState(text: string) {
  scanner.setText(text);
  scanner.setOnError((message: ts.DiagnosticMessage, length: number) => {
    console.error(message);
  });
  scanner.setScriptTarget(ts.ScriptTarget.ES5);
  scanner.setLanguageVariant(ts.LanguageVariant.Standard);
}

// 使用示例
initializeState(
  `
var foo = 123;
`.trim()
);

// 开始扫描
var token = scanner.scan();
while (token != ts.SyntaxKind.EndOfFileToken) {
  console.log(ts.formatSyntaxKind(token));
  token = scanner.scan();
}
```

该段代码输出以下内容:

```
VarKeyword
Identifier
FirstAssignment
FirstLiteralToken
SemicolonToken
```

## 扫描器状态

调用 `scan` 后,扫描器更新其局部状态(扫描位置,当前 token 详情等)。扫描器提供了一组工具函数获取当前扫描器状态。下例中,我们创建一个扫描器并用它识别 token 以及 token 在代码中的位置。

`code/compiler/scanner/runScannerWithPosition.ts`

```ts
// 使用示例
initializeState(
  `
var foo = 123;
`.trim()
);

// 开始扫描
var token = scanner.scan();
while (token != ts.SyntaxKind.EndOfFileToken) {
  let currentToken = ts.formatSyntaxKind(token);
  let tokenStart = scanner.getStartPos();
  token = scanner.scan();
  let tokenEnd = scanner.getStartPos();
  console.log(currentToken, tokenStart, tokenEnd);
}
```

该代码输出以下内容:

```
VarKeyword 0 3
Identifier 3 7
FirstAssignment 7 9
FirstLiteralToken 9 13
SemicolonToken 13 14
```

## 独立扫描器

即便 TypeScript 解析器有单例扫描器,你仍可以使用 `createScanner` 创建独立的扫描器,然后可以用 `setText`/`setTextPos` 随意扫描文件的不同位置。


================================================
FILE: docs/error/common.md
================================================
# 常见的 Error

在此章节中,我们学习在实际应用中将会遇到的常见错误代码。

## TS2304

例子:

> `Cannot find name ga`, `Cannot find name $`, `Cannot find module jquery`

你可能在使用第三方的库(如:google analytics),但是你并没有 `declare` 的声明。在没有声明它们之前,TypeScript 试图避免错误和使用变量。因此在使用一些额外的库时,你需要明确的声明使用的任何变量([如何修复它](../typings/ambient.md))。

## TS2307

例子:

> `Cannot find module 'underscore'`

你可能把第三方的库作为模块([移步模块](../project/modules.md))来使用,并且没有一个与之对应的环境声明文件([更多声明文件信息](../typings/ambient.md))。

## TS1148

例子:

> `Cannot compile modules unless the '--module' flag provided`

请查看[模块](../project/modules.md)章节

## 捕获不能有类型注解的简短变量

例子:

```ts
try {
  something();
} catch (e) {
  // 捕获不能有类型注解的简短变量
  // ...
}
```

TypeScript 正在保护你免受 JavaScript 代码的侵害,取而代之,使用类型保护:

```ts
try {
  something();
} catch (e) {
  // 捕获不能有类型注解的简短变量
  if (e instanceof Error) {
    // do...
  }
}
```

## 接口 `ElementClass` 不能同时扩展类型别名 `Component` 和 `Component`

当在编译上下文中同时含有两个 `react.d.ts`(`@types/react/index.d.ts`)会发生这种情况。

修复:

- 删除 `node_modules` 和任何 `package-lock`(或者 `yarn lock`),然后再一次 `npm install`;
- 如果这不能工作,查找无效的模块(你所使用的所用用到了 `react.d.ts` 模块应该作为 `peerDependency` 而不是作为 `dependency` 使用)并且把这个报告给相关模块。


================================================
FILE: docs/error/interpreting.md
================================================
# 解读 Errors

TypeScript 是一种专注于帮助开发人员的编程语言,当错误出现时,它会提供尽可能提供非常有用的错误信息。这对于那些信任使用者的编译器来说,可能会导致轻微的信息量过载,而不会那么实用。

让我们来看一个在 IDE 中的例子:

```ts
type SomethingComplex = {
  foo: number;
  bar: string;
};

function takeSomethingComplex(arg: SomethingComplex) {}

function getBar(): string {
  return 'some bar';
}

// 一个可能会出现的错误使用
const fail = {
  foo: 123,
  bar: getBar
};

takeSomethingComplex(fail); // 在这里 TypeScript 会报错
```

这个简单的例子,演示了一个常见的程序设计错误,它调用函数失败(`bar: getBar` 应该是 `bar: getBar()`)。幸运的是,一旦不符合类型要求,TypeScript 将会捕捉到这个错误。

## 错误分类

TypeScript 错误信息分为两类:简洁和详细。

### 简洁

简洁的错误信息是为了提供一个编译器描述的错误号以及一些相关的信息,一个简洁的错误信息类似于如下所示:

```ts
TS2345: Argument of type '{ foo: number; bar: () => string; }' is not assignable to parameter of type 'SomethingComplex'.
```

然而,它没有提供更深层次的信息,如为什么这个错误会发生。这就是详细错误所需要的原因。

## 详细

详细的错误信息类似于如下所示:

```ts
[ts]
Argument of type '{ foo: number; bar: () => string; }' is not assignable to parameter of type 'SomethingComplex'.
  Types of property 'bar' are incompatible.
    Type '() => string' is not assignable to type 'string'.
```

详细的错误信息是为了指导使用者知道为什么一些错误(在这个例子里是类型不兼容)会发生。第一行与简洁的错误信息相同,后跟一些详细的信息。你应该阅读这些详细信息,因为对于开发者的一些疑问,它都给出了问答:

```ts
ERROR: Argument of type '{ foo: number; bar: () => string; }' is not assignable to parameter of type 'SomethingComplex'.

WHY?
CAUSE ERROR: Types of property 'bar' are incompatible.

WHY?
CAUSE ERROR: Type '() => string' is not assignable to type 'string'.
```

所以,最根本的原因是:

- 在属性 `bar`
- 函数 `() => string` 它应该是一个字符串。

这能够帮助开发者修复 bar 属性的 bug(它们忘记了调用这个函数)。

## 在 IDE 中怎么提示

IDE 通常会在详细的错误提示之后显示简洁版本,如下所示:

<img :src="$withBase('/ide.png')" alt="ide"/>

- 你通常可能只会阅读「为什么」的详细信息;
- 当你想寻找相同的错误时(使用 `TSXXX` 错误编号,或者部分错误信息),使用简洁的版本。


================================================
FILE: docs/faqs/class.md
================================================
# 类

## 为什么这些空类的行为很奇怪?

> 我写下这段代码,并期望它抛出错误

```ts
class Empty {
  /* empty */
}

var e2: Empty = window;
```

请参阅此问题「[为什么所有的内容都能赋值给空的接口](./type-system-behavior.html#为什么所有的类型,都能赋值给一个空的接口?)」。值得重新思考一下这个答案的建议:一般来说,你永远不应该声明一个没有属性的类。即使对于子类也是如此:

```ts
class Base {
  important: number;
  properties: number;
}
class Alpha extends Base {}
class Bravo extends Base {}
```

`Alpha` 和 `Bravo` 的结构相同,都是继承自 `Base`,这会产生许多令人惊讶的效果,所以别这么做。如果你想让 `Alpha` 与 `Bravo` 不相同,为它们各自提供一个属性。

## 什么是名义上的类

这两段代码该如何解释:

```ts
class Alpha {
  x: number;
}
class Bravo {
  x: number;
}
class Charlie {
  private x: number;
}
class Delta {
  private x: number;
}

let a = new Alpha(),
  b = new Bravo(),
  c = new Charlie(),
  d = new Delta();

a = b; // OK
c = d; // Error
```

在 TypeScript 中,类进行结构上的比较,有一个例外是对于 `private` 与 `protected` 的成员。当一个成员是 `private` 或者 `protected` 时,它们必须来自同一个声明,才能被视为与另一个 `private` 或者 `protected` 的成员相同。

## 为什么在我的实例方法中,`this` 成了一个「孤儿」?

> 我写下如下代码

```ts
class MyClass {
  x = 10;
  someCallback() {
    console.log(this.x); // Prints 'undefined', not 10
    this.someMethod(); // Throws error "this.method is not a function"
  }
  someMethod() {}
}

let obj = new MyClass();
window.setTimeout(obj.someCallback, 10);
```

可能会提出一些相似的问题:

- 为什么在我的回调函数中类的属性没有定义?
- 为什么在我的回调函数中,`this` 指向 `window`?
- 为什么在我的回调函数中,`this` 指向 `undefined`?
- 为什么我会得到 `this.someMethod is not a function` 的错误?
- 为什么我会得到 `Cannot read property 'someMethod' of undefined` 的错误?

在 JavaScript 中,`this` 值由以下确定:

1. 该函数是调用 `.bind` 的结果吗?如果是这样,`this` 由传递给 `bind` 的第一个参数确定

2. 该函数是通过属性表达式 `expr.method() ?` 直接调用吗?如果是这样,`this` 指向 `expr`

3. 否则,`this` 是 `undefined`(在严格模式中),或者是 `window` (非严格模式中)。

在上一个例子中,影响结果的是这行代码:

```ts
window.setTimeout(obj.someCallback, 10);
```

在这里,我们提供了 `obj.someCallback` 到 `setTimeout` 的函数引用,然后该函数并不是作为 `bind` 的结果调用,也不是直接作为一个方法调用。因此在 `someCallback` 里的 `this` 指向 `window`(或者在严格模式下的 `undefied`)。

这里概述了一些解决办法:http://stackoverflow.com/a/20627988/1704166

## 当 `Bar` 是一个 `class` 时,`Bar` 和 `typeof Bar` 有什么区别?

> 我写下这段代码,但是我不理解我为什么会得到错误:

```ts
class MyClass {
  someMethod() {}
}
var x: MyClass;
// Cannot assign 'typeof MyClass' to MyClass? Huh?
x = MyClass;
```

在 JavaScript 中,类仅仅是个函数,这点很重要。我们将类对象本身 -- `MyClass` 的值,作为是构造函数。当一个构造函数被 `new` 调用时,我们得到一个对象,它是该类的实例。

因此,当我们定义一个类时,实际上,我们定义了两个不同的类型。

第一个是由类的名字推导而来,在这个例子中是 `MyClass`。这个是类实例的类型,它定义了类的实例具有的属性和方法,它是一个通过调用类的构造函数来返回的类型。

第二个类型是一个匿名的类型,它是构造函数具有的类型。它包含一个返回类实例的构造函数签名(可以使用 `new` 调用),同时,它也包含类中可能含有的 `static` 属性和方法。它也通常被称为「静态方面」,因为它包含那些静态成员(以及作为类的构造函数)。我们可以用 `typeof` 来引用此类型。

当在类型位置使用 `typeof` 操作符时,描述了表达式的类型。因此 `typeof MyClass` 是指 `MyClass` 的类型。

## 为什么我的子类属性初始值设定会覆盖基类构造函数中设置的值?

有关此问题,和其他初始化顺序问题,请参阅 [#1617](https://github.com/Microsoft/TypeScript/issues/1617)。

## 声明类和接口有什么区别?

参阅: http://stackoverflow.com/a/14348084/1704166

## 接口继承类,意味着什么?

> 这段代码是什么意思?

```ts
class Foo {
  /* ... */
}
interface Bar extends Foo {}
```

这创建了一个名叫 `Bar` 的类型,它与 `Foo` 的实例具有相同的成员。当 `Foo` 具有私有成员时,`Bar` 内的相同属性,必须由一个继承自 `Foo` 的类实现。总的来说,这种模式是应当避免的,尤其是在 `Foo` 有私有成员时。

## 为什么我会得到错误:`TypeError: [base class name] is not defined in __extends`?

> 我写下一段代码,

```ts
/** file1.ts **/
class Alpha {
  /* ... */
}

/** file2.ts **/
class Bravo extends Alpha {
  /* ... */
}
```

在运行时,有如下错误发生在 `_extends` 中:

```ts
Uncaught TypeError: Alpha is not defined
```

最常见的原因是在你的 HTML 中包含有 file2.ts 的 `script`,但是并没有包含 `file1.ts` 的 `script`。因此你需要在引用 `file2.ts` 之前引用 `file1.ts`。

## 为什么我会得到 `TypeError: Cannot read property 'prototype' of undefined" in __extends` 的错误?

> 我写下如下代码:

```ts
/** file1.ts **/
class Alpha {
  /* ... */
}

/** file2.ts **/
class Bravo extends Alpha {
  /* ... */
}
```

在运行时,有如下错误发生在 `_extends` 中:

```ts
Uncaught TypeError: Cannot read property 'prototype' of undefined
```

出现这种情况,原因可能有一些。

首先,在单个文件中,你在基类之前定义了派生类,那么你应该重新排序文件,以便在派生类之前声明基类。

如果你使用了 `--out` 的编译选项,编译器可能会对你希望文件的顺序感到困惑。请参阅常见问题简答中「如果控制文件排序」部分

如果您没有使用 `--out`,HTML 文件中的 `script` 引用文件的顺序可能出现错误。重新排序 `script` 对文件的引用,以便在定义派生类的文件之前包含定义基类的文件。

最后,如果你使用某种类型的第三方包,该包可能会错误地排序了文件。请参阅该工具的文档以了解如何在结果输出中正确排序输入文件。

## 为什么不扩展 `Error`、`Array`、`Map` 内置函数?

在 ES2015 中,返回一个对象的构造函数将 `this` 的值隐式替换为 `super(...)` 的任何调用者。这对于构造函数代码捕获 `super(...)` 的任何潜在返回值并将其替换为 `this` 是必要的。

这样导致的结果是:`Error`、`Array` 等子类将不再按预期工作。这是由于 `Error`、`Array` 等的构造函数使用 ECMAScript6 中的 `new.target` 来调整原型链。但是,在 ECMAScript 5 中调用构造函数时,无法确保 `new.target` 的值。在其他一些低水平的编译器通常都有相同的限制。

### 例如:

如下作为一个子类:

```ts
class FooError extends Error {
  constructor(m: string) {
    super(m);
  }
  sayHello() {
    return 'hello ' + this.message;
  }
}
```

你可能会发现:

- 通过这些子类的构造函数返回的对象中,方法可能是 `undefined`。因此,当调用 `sayHello` 时,会抛出一个错误。
- `instanceof` 将会在子类的实例和自身实例中被中断。因此 `new FooError() instanceof FooError` 将返回 `false`。

### 推荐

作为一个推荐方式,你可以在 `super(...)` 被调用之后手动调整原型。

```ts
class FooError extends Error {
  constructor(m: string) {
    super(m);

    // Set the prototype explicitly.
    Object.setPrototypeOf(this, FooError.prototype);
  }

  sayHello() {
    return 'hello ' + this.message;
  }
}
```

然而,任何 `FooError` 的子类将不得不手动设置原型。在运行时,对于那些不支持 `Object.setPrototypeOf` 属性的,你可能用要 `__proto__` 来替代他。

不幸的是,[IE 10 及其一下不兼容这些方法](https://docs.microsoft.com/zh-cn/microsoft-edge/dev-guide/whats-new/javascript-version-information)。你可以手动将原型中的方法复制到实例本身,(例如:`FooError.prototype` 复制到 `this` 上),但是对于原型链本身是无法修复的。


================================================
FILE: docs/faqs/commandline-behavior.md
================================================
# 命令行的行为

## 如何控制输出文件中的排序(-- out)?

输出文件的排序遵循预处理后输入文件的顺序。

编译器执行预处理,主要是为了解决所有的三斜线指令和模块导入。在这个过程中,额外的文件将会被将入到编译过程中。

这个过程开始于一个给定的根文件,这些是在命令行或者是 `tsconfig.json` 文件中 files 指定文件名,这些根文件按照指定的顺序进行预处理。在一个文件添加到这个列表之前,将处理所有的三斜线引用和模块导入语法,并包括它们的目标。三斜线引用和导入语法按照它们在文件中出现的顺序,以深度优先的方式解析。

请参考有关[三斜线指令](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html)的更多信息,和[模块](https://www.typescriptlang.org/docs/handbook/module-resolution.html)导入语法的信息。

## `Exported variable [name] has or is using private name [name]` 是什么错误?

当你使用 `--declarartion` 编译选项的时候,可能会出现这个错误,因为编译器试图生成与你定义模块完全匹配的声明文件:

假设你有这样一段代码:

```ts
/// MyFile.ts
class Test {
  // ... other members ....
  constructor(public parent: Test) {}
}

export let t = new Test('some thing');
```

为了生成声明文件,编译器必须为 `t` 写一个类型:

```ts
/// MyFile.d.ts, auto-generated
export let t: ___fill in the blank___;
```

成员 `t` 有类型 `Test`,但是类型 `Test` 并不是可见的,因为它没有导出,因此我们不能写 `t: Test`。

在这个非常简单的例子里,我们可以用一个对象字面量重写 `Test's` 的形状。但是对于绝大多数情况,这并不能正常工作。如代码里所写,Test 的形状是自引用的,不能重写为匿名函数。如果 `Test` 有任何私有或受保护的成员,这同样也不能正常工作。因此,与其让你通过编写一个真实的类来获得 65% 的成功而后开始抛出错误,我们仅仅是在一开始的时候就抛出错误(你以后会发现)并为你省去不必要的麻烦。

为了避免这些错误:

- 导出相关类型中使用的声明
- 当编写声明的时候,显示的为编译器指定类型注解

## 为什么添加 `--outDir` 属性后,当在添加一个新文件时,会把所有的输出删除

`--outDir` 指定输出的「根」目录。编译器需要此属性,用来将资源映射输出到根目录。如果 `--rootDir` 没有被指定,编辑器将会自己计算出一个。它根据常见的路径计算,它是所有输入文件的最长公共前缀。显然,当在较短路径前缀中添加新文件时,`--rootDir` 将会被修改。

为了确保添加一个新文件时,输出不会被修改,你应该在命令行中或 `tsconfig.json` 指定一个 `--rootDir`。


================================================
FILE: docs/faqs/comments.md
================================================
# 评论


================================================
FILE: docs/faqs/common-bug-not-bugs.md
================================================
# 一些常见的「bug」并不是 bug

> 注:此章节的所有文章都来自 [TypeScript FAQs](https://github.com/Microsoft/TypeScript/wiki/FAQ)

这有一些看起来像 Bug 的行为,但实际上,它们并不是。

- 两个空的类,可以彼此代替

  - 查看相关的 [FAQ](./class.html#为什么这些空类的行为很奇怪?)

- 我可以在一个返回值为 void 的函数中使用一个返回值不为 `void` 的函数

  - 查看相关的 [FAQ](./type-system-behavior.html#为什么一个返回值不是-void-的函数,可以赋值给一个返回值为-void-的函数?)
  - 查看此 [ISSUES](https://github.com/Microsoft/TypeScript/issues/4544)

- 我可以使用一个更短的参数列表,而不是一个期望的长参数列表

  - 查看相关 [FAQ](./type-system-behavior.html#为什么有更少参数的函数能够赋值给更多参数的函数?)
  - 相关 ISSUES:[#370](https://github.com/Microsoft/TypeScript/issues/370)、[#9300](https://github.com/Microsoft/TypeScript/issues/9300)、[#9765](https://github.com/Microsoft/TypeScript/issues/9765)、[#9825](https://github.com/Microsoft/TypeScript/issues/9825)、[#13043](https://github.com/Microsoft/TypeScript/issues/13043)、[#16871](https://github.com/Microsoft/TypeScript/issues/16871)、[#13529](https://github.com/Microsoft/TypeScript/issues/13529)、[#13977](https://github.com/Microsoft/TypeScript/issues/13977)、[#17868](https://github.com/Microsoft/TypeScript/issues/17868)、[#20274](https://github.com/Microsoft/TypeScript/issues/20274)、[#20541](https://github.com/Microsoft/TypeScript/issues/20541)、[#21868](https://github.com/Microsoft/TypeScript/issues/21868)。

- 类的 `private` 成员,在运行时实际上是可见的

  - 查看相关 FAQ,以及一些修复的建议
  - 相关 ISSUES:[#564](https://github.com/Microsoft/TypeScript/issues/564)、[#1537](https://github.com/Microsoft/TypeScript/issues/1537)、[#2967](https://github.com/Microsoft/TypeScript/issues/2967)、[#3151](https://github.com/Microsoft/TypeScript/issues/3151)、[#6748](https://github.com/Microsoft/TypeScript/issues/6748)、[#8847](https://github.com/Microsoft/TypeScript/issues/8847)、[#9733](https://github.com/Microsoft/TypeScript/issues/9733)、[#11033](https://github.com/Microsoft/TypeScript/issues/11033)。


================================================
FILE: docs/faqs/common-feature-request.md
================================================
# 一些常见的 Feature 需求

这有一些常见的 Feature 列表以及相应的 ISSUES,在提新的 ISSUES 之前,如果有相同的 Feature,请在相应的评论区留下评论

- 安全的导航操作符 [#16](https://github.com/Microsoft/TypeScript/issues/16)
- 最小化 [#8](https://github.com/Microsoft/TypeScript/issues/8)
- 局部的 classes [#563](https://github.com/Microsoft/TypeScript/issues/563)
- 与 `this` 相关 [#531](https://github.com/Microsoft/TypeScript/issues/531)
- 函数成员 `call/bind/apply` 的强类型 [#212](https://github.com/Microsoft/TypeScript/issues/531)
- 运行时的函数重载 [#3422](https://github.com/Microsoft/TypeScript/issues/531)


================================================
FILE: docs/faqs/decorators.md
================================================
# Decorators


================================================
FILE: docs/faqs/enums.md
================================================
# 枚举

## `enum` 和 `const enum` 之间的区别是什么?

TODO:`enum` / `const enum` 有如下区别,请看:[https://www.typescriptlang.org/docs/handbook/enums.html#enums](https://www.typescriptlang.org/docs/handbook/enums.html#enums)

================================================
FILE: docs/faqs/function.md
================================================
# 函数

## 为什么我不能在解构函数 `function f({ x: number }) { /* ... */ }` 中使用 `x`?

> 我写下这单代码,但是得到了一个错误

```ts
function f({ x: number }) {
  // Error, x is not defined?
  console.log(x);
}
```

对于那些习惯于查看 TypeScript 类型字面量的人来说,解构语法是有悖常理的。语法 `f({ x: number })` 声明了属性名从 `x` 转换为 `number` 名的解构。

让我们从发出的代码来收到启发:

```ts
function f(_a) {
  // Not really what we were going for
  var number = _a.x;
}
```

为了能让这段代码正确运行,你需要写下:

```ts
function f({ x }: { x: number }) {
  // OK
  console.log(x);
}
```

如果你想为所有属性提供一个初始变量,最合适的写法是:

```ts
function f({ x = 0 }) {
  // x: number
  console.log(x);
}
```


================================================
FILE: docs/faqs/generics.md
================================================
# 泛型

## 通过接口 `A<T>`,为什么 `A<string>` 可赋值给 `A<number>`?

> 我写下这段代码,让它抛出一个错误。

```typescript
interface Something<T> {
  name: string;
}
let x: Something<number>;
let y: Something<string>;
// Expected error: Can't convert Something<number> to Something<string>!
x = y;
```

`TypeScript` 使用了一种结构类型的系统。当判断 `Something<number>` 和 `Something<string>` 兼容性的时候,我们会检查每一个成员的每一个属性,如果类型的每个成员都是兼容的,那么这个类型也是兼容的。因为 `Something<T>` 没有在任何成员中使用 `T`,所以 `T` 是什么类型并不重要。

通常,你绝不应该有未使用类型的参数。该类型会有无法预料的兼容性(如上所示),同时在函数调用中也无法获取正确的泛型类型接口。

## 为什么类型接口不能在这个接口上运行: `interface Foo<T> { }`?

> 我写了一些这样的代码

```typescript
interface Named<T> {
  name: string;
}
class MyNamed<T> implements Named<T> {
  name: 'mine';
}
function findByName<T>(x: Named<T>): T {
  // TODO: Implement
  return undefined;
}

var x: MyNamed<string>;
var y = findByName(x); // expected y: string, got y: {}
```

`TypeScript` 使用了一种结构类型的系统。这种结构性也适用于泛型类型接口。当在函数调用中推断 `T` 的类型时,我们试图在 `x` 参数上找到 `T` 类型的成员,从而判断 `T` 应该是什么。因为没有使用 `T` 的成员,所以没有什么可推断的,于是我们返回 `{}`。

请注意,如果你使用 `T`,你就会得到正确的结果:

```typescript
interface Named<T> {
  name: string;
  value: T; // <-- added
}
class MyNamed<T> implements Named<T> {
  name: 'mine';
  value: T; // <-- added
}
function findByName<T>(x: Named<T>): T {
  // TODO: Implement
  return undefined;
}

var x: MyNamed<string>;
var y = findByName(x); // got y: string;
```

记住:你绝不应该有未使用类型的参数!请看前一个问题,了解为什么这样不好。

## 为什么不要在泛型函数中写 `typeof T`、`new T`, 或者 `instanceof T`?

> 我写了一些这样的代码

```typescript
function doSomething<T>(x: T) {
  // Can't find name T?
  let xType = typeof T;
  let y = new xType();
  // Same here?
  if(someVar instanceof typeof T) {

  }
  // How do I instantiate?
  let z = new T();
}
```

泛型在编译期间被删除,这意味着在 `doSomething` 运行时没有值为 `T` 。这里人们试图表达的正常模式是将类的构造函数用于工厂或运行时类型检查。。在这两种情况下,使用构造签名并将其作为参数提供是正确的:
```typescript
function create<T>(ctor: { new(): T }) {
  return new ctor();
}
var c = create(MyClass); // c: MyClass

function isReallyInstanceOf<T>(ctor: { new(...args: any[]): T }, obj: T) {
  return obj instanceof ctor;
}
```

================================================
FILE: docs/faqs/glossary-and-terms.md
================================================
# 术语表


================================================
FILE: docs/faqs/jsx-and-react.md
================================================
# JSX 和 React

## 我写了声明 `declare var MyComponent: React.Component`,为什么我不能写 `<MyComponent />`

> 我写下了如下代码,为什么会抛出错误?

```ts
class Display extends React.Component<any, any> {
    render() { ... }
}

let SomeThing: Display = /* ... */;
// Error here, isn't this OK?
let jsx = <SomeThing />;
```

这可能是把类的实例与静态类混淆了。当 React 实例化一个组件时,它在调用构造函数。因此当 TypeScript 看到一个 JSX 标签 `<TagName>` 时,它在验证构造函数 `TagName` 的结果是否可以产生有效组件。

但是这个声明 `let someThing: Display` 只是表明了 `someThing` 是类的实例,并不是类的构造函数。实际上,他会在运行时抛出错误:

```ts
let SomeThing = new Display();
let jsx = <SomeThing />; // Not gonna work
```

最简单的修复方式是使用 `typeof` 操作符:

```ts
let SomeThing: typeof Display = /* ... */;
```


================================================
FILE: docs/faqs/modules.md
================================================
# 模块

## 为什么我导入的模块在编译后被删除了?

> 我写了一些这样的代码

```typescript
import someModule = require('./myMod');

let x: someModule.SomeType = /* something */;
```

> 有这样的输出

```typescript
// Expected to see "var someModule = require('./myMod');" here!

var x = /* something */;
```

`TypeScript` 假定导入的模块没有副作用,所以它移除了不用于任何表达式的模块导入。

使用 `import "mod"` 语法来强制加载模块

```typescript
import './myMod'; // For side effects
```

你也可以简单调用模块,这是最常见的解决办法。

```typescript
import someModule = require('./myMod');
someModule; // Used for side effects
```

## 为什么不跨模块文件合并命名空间?

TODO:本小节内容请查看:[https://stackoverflow.com/questions/30357634/how-do-i-use-namespaces-with-typescript-external-modules](https://stackoverflow.com/questions/30357634/how-do-i-use-namespaces-with-typescript-external-modules) 或者 [https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-5.html#namespace-keyword](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-5.html#namespace-keyword)


================================================
FILE: docs/faqs/thing-that-dont-work.md
================================================
# 一些不能按预期工作的代码

## 你应该像这样发出一些类,以便于他们拥有真正的私有成员

> 如果我写下一些以下代码

```ts
class Foo {
  private x = 0;
  increment(): number {
    this.x++;
    return x;
  }
}
```

> 你应该发出这样的代码,以便 `x` 是真正的私有成员:

```ts
var Foo = (function() {
  var x = 0;

  function Foo() {}
  Foo.prototype.increment = function() {
    x++;
    return x;
  };
  return Foo;
})();
```

这些代码不会工作,它创建了一个所有类共享的单个私有字段:

```ts
var a = new Foo();
a.increment(); // Prints 1
a.increment(); // Prints 2
var b = new Foo(); // Should not affect a
a.increment(); // Prints 1
```

## 你应该发出这样的类,这样它们就不会在回调函数中丢失 `this`

> 如果我写下这样的代码

```ts
class MyClass {
  method() {}
}
```

> 你应该发出这样的代码,以便我不会在回调函数中丢失 `this`

```ts
var MyClass = (function() {
  function MyClass() {
    this.method = function() {};
  }
  return MyClass;
})();
```

这里有两个问题:

首先,建议改变的行为与 ECMAScript 规范不一致。在这方面没有任何异议 -- TypeScript 必须与 JavaScript 具有相同的运行时行为。

其次,这个运行时类的特点非常令人惊讶。它为每个实例的每个方法创建一个闭包,而不是为每个方法创建一个闭包,这在初始化时,内存、以及垃圾回收上的性能都非常糟糕。


================================================
FILE: docs/faqs/tsconfig-behavior.md
================================================
# `tsconfig.json` 的行为

## 为什么把一个文件放入「exclude」选项中,它仍然会被编译器选中?

`tsconfig.json` 将会把一个文件夹转换为「项目」,如果不指定任何 `exclude` 或者 `files`,则包含在 `tsconfig.json` 中的所有文件夹中的所有文件都会被包含在编译中。

如果你想忽略一些文件,使用 `exclude`。如果希望指定所有文件,而不是让编译器查找它们,请使用 `files`。

这些行为,`tsconfig.json` 将会自动确认。但是这有一个不同的问题,即是解析模块。模块解析:编译器将尝试去理解 `ns` 在模块语法中表示什么,即 `import * as ns from 'mod'`。为了理解它,编译器需要定义一个模块,它可能是包含你自己代码的 .ts 文件,或者是导入的一个 .d.ts 文件。如果一个文件被找到,则无论它是否在 `excludes` 中,它都将会被编译。

因此,如果你想从编译中排除一个文件,你需要排除所有具有 `import` 或者 `<reference path="...">` 指令的文件。

使用 `tsc --listFiles` 来列出在编译时包含了哪些文件,`tsc --traceResolution` 来看看它们为什么会被包含在编译中。

## 我怎么指定一个 `include`?

现在无法在 `tsconfig.json` 的 `include` 选项外指定所需要包含的文件。你可以通过以下任意一种方式获得相同的结果:1 使用 `files` 列表,2 在目录中添加 `///<reference path="">` 指令。

## 当我使用 JavaScript 文件时,为什么我会得到 `error TS5055: Cannot write file 'xxx.js' because it would overwrite input file` 错误?

对于 TypeScript 文件来说,在默认情况下,编译器将在同一目录中生成与 JavaScript 相同文件名的文件。因为 TypeScript 文件与编译后的文件总是拥有不同的后缀,这么做是安全的。然而,如果你设置 `allowJs` 编译选项为 `true` 和没有设置任何的编译输出属性(`outFile` 和 `outDir`),编译器将会尝试使用相同的规则来编译文件,这将导致发出的 JavaScript 文件与源文件具有相同的文件名。为了避免意外覆盖源文件,编译器将会发出此警告,并跳过编写输出文件。

有多种方法可以解决此问题,但所有这些方法都涉及配置编译器选项,因此建议你在项目根目录中的 tsconfig.json 文件来启用此功能。如果你不想编译 JavaScript 文件,你只需要将 `allowJs` 选项设置为 `false`;如果你确实想要包含和编译这些 JavaScript 文件,你应该设置 `outDir` 或者 `outFile` 选项,定向到其他位置,这样他们就不会与源文件冲突。如果你仅仅是想包含这些 JavaScript 文件,但是不需要编译,设置 `noEmit` 选项为 `true` 可以跳过编译检查。


================================================
FILE: docs/faqs/type-guards.md
================================================
# 类型守卫

## 为什么 `x instanceof Foo` 不能将 `x` 的类型缩小至 `Foo`?

这取决于 `x` 是什么?如果 `x` 的类型不与 `Foo` 兼容,那么缩小 `x` 的类型就毫无意义,所以我们不会这么做。

当你发现 `x` 具有任何类型时,我们对此推荐的做法是:

```ts
function doIt(x) {
  if (x instanceof Object) {
    // Assume 'x' is a well-known object which
    // we know how to handle specifically
  }

  // Treat 'x' as a primitive
}
```

你将在 TypeScript 中看到这些代码(它们可能早于联合类型被发现),或者是一些从 JavaScript 移植到 TypeScript 的代码,如果我们把 `x` 缩小至 `Object`,那么你将只能做更少的事情。使用任何不在 `Object` 中的属性都将导致错误。这不仅适用于 `Object`,对于具有已定义属性集的任何其他类型都是如此。


================================================
FILE: docs/faqs/type-system-behavior.md
================================================
# 类型系统的行为

## 什么是结构化类型?

TypeScript 使用**结构化类型**,这个系统并不同于你可能使用过的一些其他流行语言(如:Java、C# 等)的类型系统。

结构化类型系统背后的思想是如果他们的成员类型是兼容的,则他们是兼容的。例如:在 C# 或者 Java 中,有两个名为 `MyPoint` 和 `YourPoint` 的类,它们都具有公共 `int` 类型的属性 `x` 和 `y`,这两个类是不可互换的。但在结构化的类型系统中(TypeScript),这些类型具有不同名称的事实并不重要,因为它们具有相同类型的成员,所以它们是相同的(可以互换的)。

这也适用于子类型关系。例如:在 C++ 中,如果 `Animal` 是 `Dog` 的父类,你只能使用 `Dog` 来替代 `Animal`。在 TypeScript 中,并不是如此,具有至少与 `Animal` 相同数量的成员(适当的类型)的 `Dog`,才是 `Animal` 的子类型,而不管是否是继承关系。

这对于习惯于使用名义类型语言的程序员来说,会产生一些令人惊讶的结果。在这个 FAQs 中的许多问题,都可以追溯到结构化类型及其含义。一旦你掌握了它的基础知识,就很容易理解了。

## 什么是类型删除?

TypeScript 移除了类型断言、接口、类型别名和一些其他编译期间的类型结构。

输入:

```ts
var x: SomeInterface;
```

输出:

```ts
var x;
```

这意味着,在运行时,没有信息表明变量 `x` 的类型是 `SomeInterface`。

对于习惯使用反射或其他元数据系统的程序员来说,缺少的运行时类型信息可能是令人惊讶的。FAQs 中的许多问题都可以归结为「因为类型被删除」。

## 为什么没有 setter 时的 getter,没有被认为是只读?

> 我写下一段代码,并且期望它会抛出错误

```ts
class Foo {
  get bar() {
    return 42;
  }
}
let x = new Foo();
// Expected error here
x.bar = 10;
```

这在 TypeScript 2.0 + 中会抛出错误。具体请看 [#12](https://github.com/Microsoft/TypeScript/issues/12)

## 为什么函数参数是双向协变?

> 我写下一段代码,并且期望它会抛出错误

```ts
function trainDog(d: Dog) { ... }
function cloneAnimal(source: Animal, done: (result: Animal) => void): void { ... }
let c = new Cat();

// Runtime error here occurs because we end up invoking 'trainDog' with a 'Cat'
cloneAnimal(c, trainDog);
```

这是由于类型系统中缺乏显示协变/逆变注解而导致的不健全。由于它们的缺失,当被问及到 `(x: Dog) => void` 是否能够赋值给 `(x: Animal) => void` 时,TypeScript 必须更加的宽容处理。

为了理解为什么是这样,我们来思考两个问题:`Dog[]` 是 `Animal[]` 的子类型吗?在 TypeScript 中 `Dog[]` 是否应该是 `Animal[]` 的子类型?

第二个问题很容易分析,如果它的答案是 `no` 了?

```ts
function checkIfAnimalsAreAwake(arr: Animal[]) { ... }

let myPets: Dog[] = [spot, fido];

// Error? Can't substitute Dog[] for Animal[] ?
checkIfAnimalsAreAwake(myPets);
```

这将是非常烦人。在 `checkIfAnimalsAreAwake` 没有修改 arr 的情况下,这段代码 100% 是正确的。没有充足的理由来认为 `Dog[]` 不能被赋值给 `Animal[]` - 在这里很明显,一组 `Dog` 是一组 `Animal`。

回到第一个问题,类型系统什么时候会决定 `Dog[]` 是 `Animal[]` 的子类型。它将会进行以下计算(写到这里,编译器好像没有进行任何优化):

- `Dog[]` 可以被赋值给 `Animal[]` 类型吗?
- `Dog[]` 的每个成员都可以被赋值给 `Animal[]` 吗?
  - `Dog[].push` 可以赋值给 `Animal[].push` 吗?
    - 类型 `(x: Dog) => number` 可以赋值给 `(x: Animal) => number` 吗?
      - `(x: Dog) => number` 的第一个参数的类型,可以赋值给 `(x: Animal) => number` 的第一个参数吗?
        - `Dog` 可以赋值给 `Animal` 吗?
          - 是的

如你所看到的一样,类型系统在检查类型是否可以赋值时,它会提问「`(x: Dog) => number` 的类型能赋值给 `(x: Animal) => number` 吗?」,这与类型系统要求原始类型所需的问题相同。如果 TypeScript 强制函数参数进行逆变(`Animal` 可以赋值给 `Dog`),这可能会导致 `Dog[]` 并不能赋值给 `Animal[]`。

总的来说,在 TypeScript 的类型系统里,一个接收更多特定类型参数的函数是否能够赋值给一个较少特定类型参数的函数的问题,它的答案有一个先决条件 - 有更多特定类型的数组能够赋值到一个较少特定类型的数组吗?在大多数情况下,如果后者不是这情情况,则认为是不被允许的。所以我们必须对函数参数类型的特定情况进行正确的权衡。

## 为什么有更少参数的函数能够赋值给具有更多参数的函数?

> 我写下这段代码,并期望它抛出错误

```ts
function handler(arg: string) {
  // ....
}

function doSomething(callback: (arg1: string, arg2: number) => void) {
  callback('hello', 42);
}

// Expected error because 'doSomething' wants a callback of
// 2 parameters, but 'handler' only accepts 1
doSomething(handler);
```

这是预期和期望的行为。首先,参考在顶部 FAQ 中的 「substitutability」(译者注:「substitutability」会在接下来的术语专题中解释) - `handler` 是回调函数中的有效参数,因为它可以安全的忽略额外的参数。

其次,让我们来探讨下另外一个用例:

```ts
let items = [1, 2, 3];
items.forEach(arg => console.log(arg));
```

这也可以看成一个「期望的错误」。在运行时,`forEach` 使用三个参数调用指定的回调函数,但是在大多数情况下,回调函数仅仅使用一个或者两个参数。这是一种非常常见的 JavaScript 模式,必须明确声明所有未使用的参数是很麻烦的。

> 但是 `forEach` 仅仅是标记它的参数作为可选项,例如:`forEach(callback: (element?: T, index?: number, array?: T[]))`

这并不是可选回调函数的含义。始终从函数调用者的角度去读取函数签名,如果 `forEach` 声明回调函数是可选的,这意味着 `forEach` 可能会使用 0 参数来调用回调函数。

一个可选的回调函数参数的含义是:

```ts
// Invoke the provided function with 0 or 1 argument
function maybeCallWithArg(callback: (x?: number) => void) {
  if (Math.random() > 0.5) {
    callback();
  } else {
    callback(42);
  }
}
```

`forEach` 总是为其回调函数提供所有的三个参数。你不必检查 `index` 参数是否为 undefined - 它始终存在,并不是可选的。

目前在 TypeScript 没有存在一种方法可以指示回调函数的参数必须存在。注意,这种强制执行,并不会修复一个错误。换句话说,我们假设每一个回调函数中必须至少有一个参数,你可能会写下以下代码:

```ts
[1, 2, 3].forEach(() => console.log('just counting'));
//   ~~ Error, not enough arguments?
```

我们可以通过添加一个参数来修复它,但是它可能不是很正确

```ts
[1, 2, 3].forEach(x => console.log('just counting'));
// OK, but doesn't do anything different at all
```

## 为什么一个返回值不是 `void` 的函数,可以赋值给一个返回值为 `void` 的函数?

> 我写下这段代码,并期望它抛出错误

```ts
function doSomething(): number {
  return 42;
}

function callMeMaybe(callback: () => void) {
  callback();
}

// Expected an error because 'doSomething' returns number, but 'callMeMaybe'
// expects void-returning function
callMeMaybe(doSomething);
```

这是预期和期望的行为。首先,参考在顶部的 FAQ 中的 「substitutability」- 相比于 `callMeMaybe`, `doSomething` 返回「更多」的信息,`callMeMaybe` 是一个有效的替代品。

其次,让我们来探讨下另外一个用例:

```ts
let items = [1, 2];
callMeMaybe(() => items.push(3));
```

这也可以看成是一个「期望的错误」。 `Array#push` 会返回一个数字(数组的新长度),但是它使用在一个返回值为 `void` 的函数上,它是一个安全的替代品。

另外一种思考这个问题的方式是:一个返回值类型为 `void` 的函数,它会说:“无论你的返回值是否存在,我都不会检查它”。

## 为什么所有的类型,都能赋值给一个空的接口?

> 我写下这段代码,并期望它抛出错误

```ts
interface Thing {
  /* nothing here */
}
function doSomething(a: Thing) {
  // mysterious implementation here
}
// Expected some or all of these to be errors
doSomething(window);
doSomething(42);
doSomething('huh?');
```

没有成员的类型,能够被任何类型替代。在这个例子中,`window`、`42`、`huh` 都能取代 `Thing`。

通常来说,你永远不应该声明没有属性的 `interface`。

## 我可以用名义上的类型别名吗?

> 我写下这段代码,并期望它抛出错误

```ts
type SomeUrl = string;
type FirstName = string;
let x: SomeUrl = 'http://www.typescriptlang.org/';
let y: FirstName = 'Bob';
x = y; // Expected error
```

类型别名只是一个简单的别名,它们无法区分自己所表示的类型。

这有一个涉及到使用交叉类型的解决办法:

```ts
// Strings here are arbitrary, but must be distinct
type SomeUrl = string & { 'this is a url': {} };
type FirstName = string & { 'person name': {} };

// Add type assertions
let x = <SomeUrl>'';
let y = <FirstName>'bob';
x = y; // Error

// OK
let xs: string = x;
let ys: string = y;
xs = ys;
```

你需要在创建值的任何位置添加类型断言,但是它仍然可以使用 `string` 别名,并且会失去类型的安全性。

## 如何防止两种类型在结构上兼容?

> 我写下这段代码,并期望它抛出错误

```ts
interface ScreenCoordinate {
  x: number;
  y: number;
}
interface PrintCoordinate {
  x: number;
  y: number;
}
function sendToPrinter(pt: PrintCoordinate) {
  // ...
}
function getCursorPos(): ScreenCoordinate {
  // Not a real implementation
  return { x: 0, y: 0 };
}
// This should be an error
sendToPrinter(getCursorPos());
```

如果你真的希望两种类型不兼容,有一种方式添加一个 「brand」 成员:

```ts
interface ScreenCoordinate {
  _screenCoordBrand: any;
  x: number;
  y: number;
}
interface PrintCoordinate {
  _printCoordBrand: any;
  x: number;
  y: number;
}

// Error
sendToPrinter(getCursorPos());
```

 请注意,这将需要在创建「brand」的地方使用类型断言:

```ts
function getCursorPos(): ScreenCoordinate {
  // Not a real implementation
  return <ScreenCoordinate>{ x: 0, y: 0 };
}
```

另外你也可以查看此 [#202](https://github.com/Microsoft/TypeScript/issues/202) 来获取更多有关于此问题的信息;

## 如果对象实现了某个接口,我怎么在运行时检查?

> 我写下了像下面的一段代码

```ts
interface SomeInterface {
  name: string;
  length: number;
}
interface SomeOtherInterface {
  questions: string[];
}

function f(x: SomeInterface | SomeOtherInterface) {
  // Can't use instanceof on interface, help?
  if (x instanceof SomeInterface) {
    // ...
  }
}
```

在编译时期, TypeScript 的类型被删除。这意味着没有用于执行运行时类型检查的内置机制。这完全取决与你如何鉴别对象。一个比较广泛的用法是检查某个对象里的属性。你可以使用用户定义的类型保护来实现它:

```ts
function isSomeInterface(x: any): x is SomeInterface {
  return typeof x.name === 'string' && typeof x.length === 'number';

function f(x: SomeInterface|SomeOtherInterface) {
  if (isSomeInterface(x)) {
    console.log(x.name); // Cool!
  }
}
```

## 为什么错误的转化不会引起运行时的错误?

> 我写下一些代码:

```ts
let x: any = true;
let y = <string>x; // Expected: runtime error (can't convert boolean to string)
```

或者是这样:

```ts
let a: any = 'hmm';
let b = a as HTMLElement; // expected b === null
```

TypeScript 拥有类型断言,但这并不是一个「casts」:`<T> x` 仅仅是用来告诉 TypeScript:「TypeScript,请将 `x` 的类型认为是 `T`」,而不是执行类型安全的运行时转换。因为类型被删除,没有直接等价于 C# 的 `expr as` 或者是 `(type)expr` 的语法。

## 为什么我没有为 `(number) => string` 或者 `(T) => T` 进行类型检查?

> 我写下这段代码,并期望它抛出错误

```ts
let myFunc: (number) => string = n => 'The number in hex is ' + n.toString(16);
// Expected error because boolean is not number
console.log(myFunc(true));
```

在函数的类型中,参数名字是必须的。上面那段代码描述了一个参数名是 `number`,类型是 `any` 的函数。换句话说,这个声明:

```ts
let myFunc: (number) => string;
```

它等价于这个:

```ts
let myFunc: (number: any) => string;
```

你应该写成:

```ts
let myFunc: (myArgName: number) => string;
```

为了避免这些问题,你需要开启 `noImplicitAny` 选项,当检测到有任何参数的类型为 `any` 时,它将会发出一个警告。

## 为什么我会得到 `Supplied parameters do not match any signature` 的错误?

函数实现签名,它并不是重载的一部分:

```ts
function createLog(message: string): number;
function createLog(source: string, message?: string): number {
  return 0;
}

createLog('message'); // OK
createLog('source', 'message'); // ERROR: Supplied parameters do not match any signature
```

当至少具有一个函数重载的签名时,只有重载是可见的。最后一个声明签名(也可以被称为签名的实现)对签名的形状并没有贡献,因此,要获得所需的行为,你需要添加额外的重载:

```ts
function createLog(message: string): number;
function createLog(source: string, message: string): number;
function createLog(source: string, message?: string): number {
  return 0;
}
```

由于 JavaScript 没有函数重载,我们不得不这么做,因此你需要在你的函数中进行参数检查。

例如,你可以要求你的使用者使用匹配的参数对来调用,并正确实现它,而不允许混合参数类型。

```ts
function compare(a: string, b: string): void;
function compare(a: number, b: number): void;
function compare(a: string | number, b: string | number): void {
  // Just an implementation and not visible to callers
}

compare(1, 2); // OK
compare('s', 'l'); // OK
compare(1, 'l'); // Error.
```


================================================
FILE: docs/jsx/nonReactJSX.md
================================================
# 非 React JSX

TypeScript 让你能够以类型安全的方式,在 React 中使用 JSX 之外的其他东西。下面列出了一些可自定义的点,但请注意,这只适用于高级 UI 框架的作者。

- 你可以使用 `"jsx":"preserve"` 选项来禁用 React 的样式触发。这意味着,JSX 将按原样被触发,然后你可以使用自定义转化器来转化 JSX 部分。
- 使用 `JSX` 全局模块:
  - 你可以通过定制 `JSX.IntrinsicElements` 的接口成员来控制哪些 HTML 标签是可用的,以及如何对其进行类型检查;
  - 当你在组件中使用时:
    - 你可以通过自定义默认的 `interface ElementClass extends React.Component<any, any> { }` 声明文件来控制哪个 `class` 必须由组件继承;
    - 你可以通过自定义 `declare module JSX { interface ElementAttributesProperty { props: {} } }` 声明文件来控制使用的哪个属性(property)来检查特性(attribute)(默认是 `props`)。

## jsxFactory

通过 `--jsxFactory <JSX factory Name>` 与 `--jsx react`,能让你不同于默认 `React` 的方式使用 JSX 工厂函数。

这个新的工厂函数名字习惯被称之为 `createElement` 函数。

### 例子

```jsx
import { jsxFactory } from 'jsxFactory';

const div = <div>Hello JSX!</div>;
```

使用编译:

```ts
tsc --jsx react --reactNamespace jsxFactory --m commonJS
```

编译结果:

```js
'use strict';
var jsxFactory_1 = require('jsxFactory');
var div = jsxFactory_1.jsxFactory.createElement('div', null, 'Hello JSX!');
```

### jsx 编译提示

你甚至可以使用`jsxPragma` 为每个文件指定不同的 `jsxFactory`:

```tsx
/** @jsx jsxFactory */
import { jsxFactory } from 'jsxFactory';

var div = <div>Hello JSX!</div>;
```

在 jsx 编译提示中,配合 `--jsx react` 命令,这个文件将会被触发使用工厂函数:

```js
'use strict';
var jsxFactory_1 = require('jsxFactory');
var div = jsxFactory_1.jsxFactory.createElement('div', null, 'Hello JSX!');
```


================================================
FILE: docs/jsx/reactJSX.md
================================================
# React JSX

> [在 React 中使用 TypeScript 的教学视频](https://egghead.io/courses/use-typescript-to-develop-react-applications)

## 建立

在 [TypeScript in the browser](https://basarat.gitbooks.io/typescript/content/docs/quick/browser.html) 章节中,我们已经学会开始开发 React 的应用了,以下是一些重点:

- 使用文件后缀 `.tsx`(替代 `.ts`);
- 在你的 `tsconfig.json` 配置文件的 `compilerOptions` 里设置选项 `"jsx": "react"`;
- 在你的项目里为 `JSX` 和 `React` 安装声明文件:`npm i -D @types/react @types/react-dom`;
- 导入 `react` 到你的 `.tsx` 文件(`import * as React from 'react'`)。

## HTML 标签 vs 组件

React 不但能渲染 HTML 标签(strings)也能渲染 React 组件(classes)。JavaScript 触发这些的原理是不同的(`React.createElement('div')` vs `React.createElement(MyComponent)`), 确定使用哪一种方式取决于首字母的大小写,`foo` 被认为是 HTML 标签,`Foo` 被认为是一个组件。

## 类型检查

### HTML 标签

一个 HTML 标签 `foo` 被标记为 `JSX.IntrinsicElements.foo` 类型。在我们已经安装的文件 `react-jsx.d.ts` 中定义了所有主要标签的类型,如下是一部分示例:

```ts
declare namespace JSX {
  interface IntrinsicElements {
    a: React.HTMLAttributes;
    abbr: React.HTMLAttributes;
    div: React.HTMLAttributes;
    span: React.HTMLAttributes;

    // 其他
  }
}
```

### 函数式组件

你可以使用 `React.FunctionComponent` 接口定义函数组件:

```tsx
type Props = {
  foo: string;
};

const MyComponent: React.FunctionComponent<Props> = props => {
  return <span>{props.foo}</span>;
};

<MyComponent foo="bar" />;
```

### 类组件

根据组件的 `props` 属性对组件进行类型检查。这是以 JSX 如何转换作为蓝本,例如:属性成为 `props` 的组成部分。

`react.d.ts` 文件定义了 `React.Component<Props,State>`,你应该使用自己所需的 `Props` 和 `State` 声明扩展它:

```tsx
type Props = {
  foo: string;
};

class MyComponent extends React.Component<Props, {}> {
  render() {
    return <span>{this.props.foo}</span>;
  }
}

<MyComponent foo="bar" />;
```

### React JSX Tip: 接收组件的实例

react 类型声明文件提供了 `React.ReactElement<T>`,它可以让你通过传入 `<T/>`,来注解类组件的实例化结果。

```ts
class MyAwesomeComponent extends React.Component {
  render() {
    return <div>Hello</div>;
  }
}

const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error!
```

::: tip
当然,你可以将它用作函数参数的注解,甚至可以是 React 组件的 prop 成员。
:::

### React JSX Tip: 接受一个可以在 Props 起作用,并使用 JSX 渲染的组件

类型 `React.Component<Props>` 是 `React.ComponentClass<P>` 与 `React.StatelessComponent<P>` 的组合,所以你可以接受一些可以用作 Props 类型和使用 JSX 渲染的组件。

```ts
const X: React.Component<Props> = foo; // from somewhere

// Render X with some props:
<X {...props} />;
```

### React JSX Tip: 可渲染的接口

React 可以渲染一些像 `JSX` 或者是 `string` 的内容,这些被合并到类型 `React.ReactNode` 中,因此,当你接收可渲染的内容时,你可以使用它:

```tsx
type Props = {
  header: React.ReactNode;
  body: React.ReactNode;
};

class MyComponent extends React.Component<Props, {}> {
  render() {
    return (
      <div>
        {this.props.header}
        {this.props.body}
      </div>
    );
  }
}

<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />
```

### React JSX tip: 接收组件的接口

React 声明文件提供 `React.ReactElement<T>` 的接口,可以让你注解一个类组件实例化的返回值`<T/>`,如:

```tsx
class MyAwesomeComponent extends React.Component {
  render() {
    return <div>Hello</div>;
  }
}

const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error!
```

::: tip
你也可以将其用做函数参数的注解,或者是 React 组件的 prop 注解。
:::

### React JSX tip: 接收可以作为 props 的组件,并且使用 JSX 渲染它

类型 `React.Component<Props>` 合并了 `React.ComponentClass<P>` 和 `React.StatelessComponent<P>`,因此,你可以接收一些使用 `Prop` 类型的组件,并使用 JSX 渲染它:

```tsx
const X: React.Component<Props> = foo // 来自其他地方

// 渲染 X
<X {...props} />
```

### React JSX tip: 泛型组件

它完全能按我们预期工作,如:

```tsx
// 一个泛型组件
type SelectProps<T> = { items: T[] };
class Select<T> extends React.Component<SelectProps<T>, any> {}

// 使用
const Form = () => <Select<string> items={['a', 'b']} />;
```

### 泛型函数

一些像下面这样的正常工作:

```ts
function foo<T>(x: T): T {
  return x;
}
```

然而不能使用箭头泛型函数:

```ts
const foo = <T>(x: T) => T; // Error: T 标签没有关闭
```

**解决办法**:在泛型参数里使用 `extends` 来提示编译器,这是个泛型:

```ts
const foo = <T extends {}>(x: T) => x;
```

### React Tip: 强类型的 Refs

基本上你在初始化一个变量时,使用 ref 和 null 的联合类型,并且在回调函数中初始化他:

```ts
class Example extends React.Component {
  example() {
    // ... something
  }

  render() {
    return <div>Foo</div>;
  }
}

class Use {
  exampleRef: Example | null = null;

  render() {
    return <Example ref={exampleRef => (this.exampleRef = exampleRef)} />;
  }
}
```

使用原生元素时也一样:

```ts
class FocusingInput extends React.Component<{ value: string; onChange: (value: string) => any }, {}> {
  input: HTMLInputElement | null = null;

  render() {
    return (
      <input
        ref={input => (this.input = input)}
        value={this.props.value}
        onChange={e => {
          this.props.onChange(e.target.value);
        }}
      />
    );
  }
  focus() {
    if (this.input != null) {
      this.input.focus();
    }
  }
}
```

### 类型断言

如我们之前[提到](../typings/typeAssertion.md#as-foo-与-foo)的,可以使用 `as Foo` 语法进行类型断言。

## 默认 Props

- 在有状态组件中使用默认的 Props:你可以通过 `null` 操作符(这不是一个理想的方式,但是这是我能想到的最简单的最小代码解决方案)告诉 TypeScript 一个属性将会被外部提供(React)。

```tsx
class Hello extends React.Component<{
  /**
   * @default 'TypeScript'
   */
  compiler?: string;
  framework: string;
}> {
  static defaultProps = {
    compiler: 'TypeScript'
  };
  render() {
    const compiler = this.props.compiler!;
    return (
      <div>
        <div>{compiler}</div>
        <div>{this.props.framework}</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Hello framework="React" />, // TypeScript React
  document.getElementById('root')
);
```

- 在 SFC 中使用默认的 Props:推荐使用简单的 JavaScript 参数,因为同样适用于 TypeScript 类型系统:

```tsx
const Hello: React.SFC<{
  /**
   * @default 'TypeScript'
   */
  compiler?: string;
  framework: string;
}> = ({
  compiler = 'TypeScript', // Default prop
  framework
}) => {
  return (
    <div>
      <div>{compiler}</div>
      <div>{framework}</div>
    </div>
  );
};

ReactDOM.render(
  <Hello framework="React" />, // TypeScript React
  document.getElementById('root')
);
```


================================================
FILE: docs/jsx/support.md
================================================
# 支持 JSX

TypeScript 支持 JSX 转换和代码分析,如果你还不了解 JSX,[官网](https://facebook.github.io/jsx/)上有关于它的摘要:

> JSX is an XML-like syntax extension to ECMAScript without any defined semantics. It's NOT intended to be implemented by engines or browsers. It's NOT a proposal to incorporate JSX into the ECMAScript spec itself. It's intended to be used by various preprocessors (transpilers) to transform these tokens into standard ECMAScript.

JSX 背后的动机是允许用户在 JavaScript 中书写类似于 HTML 的视图,因此你可以:

- 使用相同代码,既能检查你的 JavaScript,同时能检查你的 HTML 视图层部分。
- 让视图层了解运行时的上下文(加强传统 MVC 中的控制器与视图连接)。
- 复用 JavaScript 设计模式维护 HTML 部分,例如:用 `Array.prototype.map.`、`?:`、`switch` 等,代替创建新的可替代品。

这能够减少错误的可能性,并且能增加用户界面的可维护性。目前 JSX 的主要消费者来自 [facebook 推出的 ReactJS](http://facebook.github.io/react/),接下来我们结合它来讨论 JSX 用法。

================================================
FILE: docs/new/typescript-3.7.md
================================================
# TypeScript 3.7

## 可选链(Optional Chaining)

在我们的 issue 追踪器中,可选链在 [issue #16](https://github.com/microsoft/TypeScript/issues/16) 中,自那以后,有超过 23000 条 issues 被记录在 issue 中。

可选链的核心是允许我们写下如果碰到 `null` 或者 `undefined`,TypeScript 能立即停止运行的代码。可选链耀眼的部分是使用 `?.` 运算符来访问一个可选属性的运算符。

下面代码:

```ts
let x = foo?.bar.baz();
```

告诉我们,当 `foo` 被定义了,`foo.bar.baz()` 将会执行完成;但是当 `foo` 是 `null` 或者 `undefined` 时,TypeScript 会立即停止运行,并且仅仅是返回 `undefined`。

也就是说,上文的代码等效于如下代码:

```ts
let x = foo === null || foo === undefined ? undefined : foo.bar.baz();
```

注意,如果 `bar` 是 `null` 或者 `undefined`,在访问 `bar` 时,我们的代码仍然会抛出一个错误。

与此相似,如果 `baz` 是 `null` 或者 `undefined`,在调用时,它也会抛出一个错误。`?.` 只会检查它左边的值是 `undefined` 还是 `null` - 并不会检查后面的任何属性。

你可能已经发现你可以使用 `?.` 来替代很多使用 `&&` 执行空检查的代码:

```ts
// Before
if (foo && foo.bar && foo.bar.baz) {
    // ...
}

// After-ish
if (foo?.bar?.baz) {
    // ...
}
```

注意:`?.` 与 `&&` 运算符行为略有不同,因为 `&&` 专用于 "falsy" 的值(如:空字符串、`0`、`NaN`、和 `false`),但是 `?.` 是一个仅作用于结构上的操作符,`?.` 在验证有效数据如 `0` 或者空字符串时,它并没有使用短路验证的方式。

可选链还包含另外两个运算符,首先是可选元素的访问,它的行为类似于可选属性的访问,但是它允许我们访问非标志符属性(例如:任意的字符串、数字和 symbols):

```ts
/**
 * Get the first element of the array if we have an array.
 * Otherwise return undefined.
 */
function tryGetFirstElement<T>(arr?: T[]) {
    return arr?.[0];
    // equivalent to
    //   return (arr === null || arr === undefined) ?
    //       undefined :
    //       arr[0];
}
```

另外一个是可选调用,它能让我们有条件的调用表达式:

```ts
async function makeRequest(url: string, log?: (msg: string) => void) {
    log?.(`Request started at ${new Date().toISOString()}`);
    // roughly equivalent to
    //   if (log != null) {
    //       log(`Request started at ${new Date().toISOString()}`);
    //   }

    const result = (await fetch(url)).json();

    log?.(`Request finished at at ${new Date().toISOString()}`);

    return result;
}
```

可选链的「短路运算」行为被局限在属性的访问、调用以及元素的访问 --- 它不会沿伸到后续的表达式中,也就是说:

```ts
let result = foo?.bar / someComputation()
```

可选链不会阻止除法运算或者 `someComputation()` 调用,它等价于:

```ts
let temp = foo === null || foo === undefined ? undefined : foo.bar;

let result = temp / someComputation();
```

它可能会导致除法运算的结果是 `undefined`,这就是为什么在 `strictNullChecks` 选项下,会抛出一个错误:

```ts
function barPercentage(foo?: { bar: number }) {
    return foo?.bar / 100;
    //     ~~~~~~~~
    // Error: Object is possibly undefined.
}
```

更多的信息,你可以阅读 [proposal](https://github.com/tc39/proposal-optional-chaining/) 以及该原始的 [P
Download .txt
gitextract_e5a6gj6_/

├── .all-contributorsrc
├── .gitattributes
├── .github/
│   └── workflows/
│       └── gh-pages.yml
├── .gitignore
├── .huskyrc.js
├── .prettierrc
├── LICENSE
├── README.md
├── commitlint.config.js
├── docs/
│   ├── .vuepress/
│   │   ├── config.js
│   │   ├── public/
│   │   │   └── manifest.json
│   │   └── theme/
│   │       ├── components/
│   │       │   ├── Ads.vue
│   │       │   ├── AlgoliaSearchBox.vue
│   │       │   ├── DropdownLink.vue
│   │       │   ├── DropdownTransition.vue
│   │       │   ├── Home.vue
│   │       │   ├── NavLink.vue
│   │       │   ├── NavLinks.vue
│   │       │   ├── Navbar.vue
│   │       │   ├── Page.vue
│   │       │   ├── Sidebar.vue
│   │       │   ├── SidebarButton.vue
│   │       │   ├── SidebarGroup.vue
│   │       │   ├── SidebarLink.vue
│   │       │   └── SidebarLinks.vue
│   │       ├── global-components/
│   │       │   └── Badge.vue
│   │       ├── index.js
│   │       ├── layouts/
│   │       │   ├── 404.vue
│   │       │   └── Layout.vue
│   │       ├── styles/
│   │       │   ├── arrow.styl
│   │       │   ├── code.styl
│   │       │   ├── custom-blocks.styl
│   │       │   ├── mobile.styl
│   │       │   ├── theme.styl
│   │       │   ├── toc.styl
│   │       │   └── wrapper.styl
│   │       └── util/
│   │           └── index.js
│   ├── README.md
│   ├── compiler/
│   │   ├── ast.md
│   │   ├── binder.md
│   │   ├── checker.md
│   │   ├── emitter.md
│   │   ├── overview.md
│   │   ├── parser.md
│   │   ├── program.md
│   │   └── scanner.md
│   ├── error/
│   │   ├── common.md
│   │   └── interpreting.md
│   ├── faqs/
│   │   ├── class.md
│   │   ├── commandline-behavior.md
│   │   ├── comments.md
│   │   ├── common-bug-not-bugs.md
│   │   ├── common-feature-request.md
│   │   ├── decorators.md
│   │   ├── enums.md
│   │   ├── function.md
│   │   ├── generics.md
│   │   ├── glossary-and-terms.md
│   │   ├── jsx-and-react.md
│   │   ├── modules.md
│   │   ├── thing-that-dont-work.md
│   │   ├── tsconfig-behavior.md
│   │   ├── type-guards.md
│   │   └── type-system-behavior.md
│   ├── jsx/
│   │   ├── nonReactJSX.md
│   │   ├── reactJSX.md
│   │   └── support.md
│   ├── new/
│   │   ├── typescript-3.7.md
│   │   ├── typescript-3.8.md
│   │   └── typescript-3.9.md
│   ├── project/
│   │   ├── compilationContext.md
│   │   ├── declarationspaces.md
│   │   ├── dynamicImportExpressions.md
│   │   ├── modules.md
│   │   └── namespaces.md
│   ├── tips/
│   │   ├── avoidExportDefault.md
│   │   ├── barrel.md
│   │   ├── bind.md
│   │   ├── buildToggles.md
│   │   ├── classAreUseful.md
│   │   ├── covarianceAndContravariance.md
│   │   ├── createArrays.md
│   │   ├── curry.md
│   │   ├── functionParameters.md
│   │   ├── infer.md
│   │   ├── lazyObjectLiteralInitialization.md
│   │   ├── limitPropertySetters.md
│   │   ├── metadata.md
│   │   ├── nominalTyping.md
│   │   ├── outFileCaution.md
│   │   ├── singletonPatern.md
│   │   ├── statefulFunctions.md
│   │   ├── staticConstructors.md
│   │   ├── stringBasedEmuns.md
│   │   ├── truthy.md
│   │   ├── typeInstantiation.md
│   │   └── typesafeEventEmitter.md
│   └── typings/
│       ├── ambient.md
│       ├── callable.md
│       ├── discrominatedUnion.md
│       ├── enums.md
│       ├── exceptionsHanding.md
│       ├── freshness.md
│       ├── functions.md
│       ├── generices.md
│       ├── indexSignatures.md
│       ├── interfaces.md
│       ├── lib.md
│       ├── literals.md
│       ├── migrating.md
│       ├── mixins.md
│       ├── movingTypes.md
│       ├── neverType.md
│       ├── overview.md
│       ├── readonly.md
│       ├── thisType.md
│       ├── typeAssertion.md
│       ├── typeCompatibility.md
│       ├── typeGuard.md
│       ├── typeInference.md
│       └── types.md
└── package.json
Download .txt
SYMBOL INDEX (17 symbols across 2 files)

FILE: docs/.vuepress/theme/index.js
  method alias (line 5) | alias() {

FILE: docs/.vuepress/theme/util/index.js
  function normalize (line 6) | function normalize(path) {
  function getHash (line 12) | function getHash(path) {
  function isExternal (line 19) | function isExternal(path) {
  function isMailto (line 23) | function isMailto(path) {
  function isTel (line 27) | function isTel(path) {
  function ensureExt (line 31) | function ensureExt(path) {
  function isActive (line 45) | function isActive(route, path) {
  function resolvePage (line 56) | function resolvePage(pages, rawPath, base) {
  function resolvePath (line 73) | function resolvePath(relative, base, append) {
  function resolveSidebarItems (line 118) | function resolveSidebarItems(page, regularPath, site, localePath) {
  function resolveHeaders (line 141) | function resolveHeaders(page) {
  function groupHeaders (line 160) | function groupHeaders(headers) {
  function resolveNavLinkItem (line 174) | function resolveNavLinkItem(linkItem) {
  function resolveMatchingConfig (line 185) | function resolveMatchingConfig(regularPath, config) {
  function ensureEndingSlash (line 203) | function ensureEndingSlash(path) {
  function resolveItem (line 207) | function resolveItem(item, pages, base, groupDepth = 1) {
Condensed preview — 122 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (367K chars).
[
  {
    "path": ".all-contributorsrc",
    "chars": 21040,
    "preview": "{\n  \"projectName\": \"typescript-book-chinese\",\n  \"projectOwner\": \"jkchao\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https:/"
  },
  {
    "path": ".gitattributes",
    "chars": 33,
    "preview": "*.js linguist-language=TypeScript"
  },
  {
    "path": ".github/workflows/gh-pages.yml",
    "chars": 578,
    "preview": "name: github pages\n\non:\n  pull_request:\n    types: [closed]\n    branches:\n      - master\n\n  push:\n    branches:\n      - "
  },
  {
    "path": ".gitignore",
    "chars": 175,
    "preview": ".DS_Store\nnode_modules/\ndist\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Editor directories and files\n.idea\n.vscod"
  },
  {
    "path": ".huskyrc.js",
    "chars": 123,
    "preview": "module.exports = {\n  hooks: {\n    'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS'\n    // 'pre-commit': 'lint-staged'\n  }\n"
  },
  {
    "path": ".prettierrc",
    "chars": 225,
    "preview": "{\n  \"printWidth\": 120,\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"trailingComma\": \"none\",\n  \"bracketSpacing\": true,\n  \"js"
  },
  {
    "path": "LICENSE",
    "chars": 1059,
    "preview": "MIT License\n\nCopyright (c) 2018 三毛\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this"
  },
  {
    "path": "README.md",
    "chars": 25844,
    "preview": "# 深入理解 TypeScript\n\n[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)]("
  },
  {
    "path": "commitlint.config.js",
    "chars": 349,
    "preview": "const types = ['build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test', 'chore', 'update'];\n"
  },
  {
    "path": "docs/.vuepress/config.js",
    "chars": 5249,
    "preview": "module.exports = {\n  base: '/typescript-book-chinese/',\n  title: '深入理解 TypeScript',\n  description: 'TypeScript Deep Dive"
  },
  {
    "path": "docs/.vuepress/public/manifest.json",
    "chars": 1010,
    "preview": "{\n  \"name\": \"TypeScriptBook\",\n  \"short_name\": \"TypeScriptBook\",\n  \"icons\": [\n    {\n      \"src\": \"/icons/android-chrome-3"
  },
  {
    "path": "docs/.vuepress/theme/components/Ads.vue",
    "chars": 679,
    "preview": "<template>\n  <div class=\"ads\">\n    <div\n      class=\"item\"\n      v-for=\"ads in $themeConfig.adsConfig\">\n      <h6 class="
  },
  {
    "path": "docs/.vuepress/theme/components/AlgoliaSearchBox.vue",
    "chars": 4125,
    "preview": "<template>\n  <form\n    id=\"search-form\"\n    class=\"algolia-search-wrapper search-box\"\n    role=\"search\"\n  >\n    <input\n "
  },
  {
    "path": "docs/.vuepress/theme/components/DropdownLink.vue",
    "chars": 3962,
    "preview": "<template>\n  <div\n    class=\"dropdown-wrapper\"\n    :class=\"{ open }\"\n  >\n    <a\n      class=\"dropdown-title\"\n      @clic"
  },
  {
    "path": "docs/.vuepress/theme/components/DropdownTransition.vue",
    "chars": 560,
    "preview": "<template>\n  <transition\n    name=\"dropdown\"\n    @enter=\"setHeight\"\n    @after-enter=\"unsetHeight\"\n    @before-leave=\"se"
  },
  {
    "path": "docs/.vuepress/theme/components/Home.vue",
    "chars": 3322,
    "preview": "<template>\n  <main class=\"home\" aria-labelledby=\"main-title\">\n    <header class=\"hero\">\n      <img\n        v-if=\"data.he"
  },
  {
    "path": "docs/.vuepress/theme/components/NavLink.vue",
    "chars": 882,
    "preview": "<template>\n  <router-link\n    class=\"nav-link\"\n    :to=\"link\"\n    v-if=\"!isExternal(link)\"\n    :exact=\"exact\"\n  >{{ item"
  },
  {
    "path": "docs/.vuepress/theme/components/NavLinks.vue",
    "chars": 3645,
    "preview": "<template>\n  <nav\n    class=\"nav-links\"\n    v-if=\"userLinks.length || repoLink\"\n  >\n    <!-- user links -->\n    <div\n   "
  },
  {
    "path": "docs/.vuepress/theme/components/Navbar.vue",
    "chars": 3269,
    "preview": "<template>\n  <header class=\"navbar\">\n    <SidebarButton @toggle-sidebar=\"$emit('toggle-sidebar')\"/>\n\n    <router-link\n  "
  },
  {
    "path": "docs/.vuepress/theme/components/Page.vue",
    "chars": 5450,
    "preview": "<template>\n  <main class=\"page\">\n    <slot name=\"top\"/>\n\n    <Ads></Ads>\n\n    <Content/>\n\n    <footer class=\"page-edit\">"
  },
  {
    "path": "docs/.vuepress/theme/components/Sidebar.vue",
    "chars": 1418,
    "preview": "<template>\n  <aside class=\"sidebar\">\n    <NavLinks/>\n    <slot name=\"top\"/>\n    <Ads></Ads>\n    <SidebarLinks :depth=\"0\""
  },
  {
    "path": "docs/.vuepress/theme/components/SidebarButton.vue",
    "chars": 919,
    "preview": "<template>\n  <div class=\"sidebar-button\" @click=\"$emit('toggle-sidebar')\">\n    <svg class=\"icon\" xmlns=\"http://www.w3.or"
  },
  {
    "path": "docs/.vuepress/theme/components/SidebarGroup.vue",
    "chars": 2843,
    "preview": "<template>\n  <section\n    class=\"sidebar-group\"\n    :class=\"[\n      {\n        collapsable,\n        'is-sub-group': depth"
  },
  {
    "path": "docs/.vuepress/theme/components/SidebarLink.vue",
    "chars": 2835,
    "preview": "<script>\nimport { isActive, hashRE, groupHeaders } from '../util'\n\nexport default {\n  functional: true,\n\n  props: ['item"
  },
  {
    "path": "docs/.vuepress/theme/components/SidebarLinks.vue",
    "chars": 1684,
    "preview": "<template>\n  <ul\n    class=\"sidebar-links\"\n    v-if=\"items.length\"\n  >\n    <li v-for=\"(item, i) in items\" :key=\"i\">\n    "
  },
  {
    "path": "docs/.vuepress/theme/global-components/Badge.vue",
    "chars": 811,
    "preview": "<script>\nexport default {\n  functional: true,\n  props: {\n    type: {\n      type: String,\n      default: 'tip'\n    },\n   "
  },
  {
    "path": "docs/.vuepress/theme/index.js",
    "chars": 787,
    "preview": "const path = require('path');\n\n// Theme API.\nmodule.exports = (options, ctx) => ({\n  alias() {\n    const { themeConfig, "
  },
  {
    "path": "docs/.vuepress/theme/layouts/404.vue",
    "chars": 558,
    "preview": "<template>\n  <div class=\"theme-container\">\n    <div class=\"content\">\n      <h1>404</h1>\n      <blockquote>{{ getMsg() }}"
  },
  {
    "path": "docs/.vuepress/theme/layouts/Layout.vue",
    "chars": 3159,
    "preview": "<template>\n  <div\n    class=\"theme-container\"\n    :class=\"pageClasses\"\n    @touchstart=\"onTouchStart\"\n    @touchend=\"onT"
  },
  {
    "path": "docs/.vuepress/theme/styles/arrow.styl",
    "chars": 577,
    "preview": "@require './config'\n\n.arrow\n  display inline-block\n  width 0\n  height 0\n  &.up\n    border-left 4px solid transparent\n   "
  },
  {
    "path": "docs/.vuepress/theme/styles/code.styl",
    "chars": 2801,
    "preview": ".content\n  code\n    color lighten($textColor, 20%)\n    padding 0.25rem 0.5rem\n    margin 0\n    font-size 0.85em\n    back"
  },
  {
    "path": "docs/.vuepress/theme/styles/custom-blocks.styl",
    "chars": 1041,
    "preview": ".custom-block\n  .custom-block-title\n    font-weight 600\n    margin-bottom -0.4rem\n  &.tip, &.warning, &.danger\n    paddi"
  },
  {
    "path": "docs/.vuepress/theme/styles/mobile.styl",
    "chars": 724,
    "preview": "@require './config'\n\n$mobileSidebarWidth = $sidebarWidth * 0.82\n\n// narrow desktop / iPad\n@media (max-width: $MQNarrow)\n"
  },
  {
    "path": "docs/.vuepress/theme/styles/theme.styl",
    "chars": 3150,
    "preview": "@require './code'\n@require './custom-blocks'\n@require './arrow'\n@require './wrapper'\n@require './toc'\n\nhtml, body\n  padd"
  },
  {
    "path": "docs/.vuepress/theme/styles/toc.styl",
    "chars": 54,
    "preview": ".table-of-contents\n  .badge\n    vertical-align middle\n"
  },
  {
    "path": "docs/.vuepress/theme/styles/wrapper.styl",
    "chars": 183,
    "preview": "$wrapper\n  max-width $contentWidth\n  // margin 0 2rem\n  padding 2rem 2.5rem\n  @media (max-width: $MQNarrow)\n    padding "
  },
  {
    "path": "docs/.vuepress/theme/util/index.js",
    "chars": 5747,
    "preview": "export const hashRE = /#.*$/;\nexport const extRE = /\\.(md|html)$/;\nexport const endingSlashRE = /\\/$/;\nexport const outb"
  },
  {
    "path": "docs/README.md",
    "chars": 1732,
    "preview": "# 深入理解 TypeScript\n\n此书是 [《TypeScript Deep Dive》](https://github.com/basarat/typescript-book/) 的中文翻译版,感谢作者 [Basarat](https"
  },
  {
    "path": "docs/compiler/ast.md",
    "chars": 3802,
    "preview": "# 抽象语法树\n\n### Node 节点\n\n节点是抽象语法树(AST) 的基本构造块。语法上,通常 `Node` 表示非末端(non-terminals)节点。但是,有些末端节点,如:标识符和字面量也会保留在树中。\n\nAST 节点文档由两个"
  },
  {
    "path": "docs/compiler/binder.md",
    "chars": 11119,
    "preview": "# 绑定器\n\n大多数的 JavaScript 转译器(transpiler)都比 TypeScript 简单,因为它们几乎没提供代码分析的方法。典型的 JavaScript 转换器只有以下流程:\n\n```\n源码 ~~扫描器~~> Token"
  },
  {
    "path": "docs/compiler/checker.md",
    "chars": 1755,
    "preview": "# 检查器\n\n如前所述,*检查器*使得 TypeScript 更独特,比*其它 JavaScript 转译器*更强大。检查器位于 `checker.ts` 中,当前有 23k 行以上的代码(编译器中最大的部分)\n\n### 程序对检查器的使用"
  },
  {
    "path": "docs/compiler/emitter.md",
    "chars": 15375,
    "preview": "# 发射器\n\nTypeScript 编译器提供了两个发射器:\n\n- `emitter.ts`:可能是你最感兴趣的发射器,它是 TS -> JavaScript 的发射器\n- `declarationEmitter.ts`:这个发射器用于为 "
  },
  {
    "path": "docs/compiler/overview.md",
    "chars": 1788,
    "preview": "# 概览\n\nTypeScript 编译器源文件位于 [`src/compiler`](https://github.com/Microsoft/TypeScript/tree/master/src/compiler) 目录下\n\n> 译注:T"
  },
  {
    "path": "docs/compiler/parser.md",
    "chars": 3031,
    "preview": "# 解析器\n\nTypeScript 解析器代码均位于 `parser.ts` 中。在内部,由解析器控制扫描器将源码转化为 AST。其期望结果如下:\n\n```\n源码 ~~ 扫描器 ~~> Token 流 ~~ 解析器 ~~> AST\n```\n"
  },
  {
    "path": "docs/compiler/program.md",
    "chars": 509,
    "preview": "# 程序\n\n程序定义在 `program.ts` 中。[编译上下文](../project/compilationContext.md)在 TypeScript 编译器中被视为一个 `Program`,它包含 `SourceFile` 和编"
  },
  {
    "path": "docs/compiler/scanner.md",
    "chars": 1817,
    "preview": "# 扫描器\n\nTypeScript 扫描器的源码均位于 `scanner.ts`。在内部,由解析器*控制*扫描器将源码转化为抽象语法树(AST)。期望结果如下:\n\n```\nSourceCode ~~ 扫描器 ~~> Token 流 ~~ 解"
  },
  {
    "path": "docs/error/common.md",
    "chars": 1124,
    "preview": "# 常见的 Error\n\n在此章节中,我们学习在实际应用中将会遇到的常见错误代码。\n\n## TS2304\n\n例子:\n\n> `Cannot find name ga`, `Cannot find name $`, `Cannot find m"
  },
  {
    "path": "docs/error/interpreting.md",
    "chars": 1686,
    "preview": "# 解读 Errors\n\nTypeScript 是一种专注于帮助开发人员的编程语言,当错误出现时,它会提供尽可能提供非常有用的错误信息。这对于那些信任使用者的编译器来说,可能会导致轻微的信息量过载,而不会那么实用。\n\n让我们来看一个在 ID"
  },
  {
    "path": "docs/faqs/class.md",
    "chars": 5227,
    "preview": "# 类\n\n## 为什么这些空类的行为很奇怪?\n\n> 我写下这段代码,并期望它抛出错误\n\n```ts\nclass Empty {\n  /* empty */\n}\n\nvar e2: Empty = window;\n```\n\n请参阅此问题「[为什"
  },
  {
    "path": "docs/faqs/commandline-behavior.md",
    "chars": 1433,
    "preview": "# 命令行的行为\n\n## 如何控制输出文件中的排序(-- out)?\n\n输出文件的排序遵循预处理后输入文件的顺序。\n\n编译器执行预处理,主要是为了解决所有的三斜线指令和模块导入。在这个过程中,额外的文件将会被将入到编译过程中。\n\n这个过程开"
  },
  {
    "path": "docs/faqs/comments.md",
    "chars": 5,
    "preview": "# 评论\n"
  },
  {
    "path": "docs/faqs/common-bug-not-bugs.md",
    "chars": 1820,
    "preview": "# 一些常见的「bug」并不是 bug\n\n> 注:此章节的所有文章都来自 [TypeScript FAQs](https://github.com/Microsoft/TypeScript/wiki/FAQ)\n\n这有一些看起来像 Bug 的"
  },
  {
    "path": "docs/faqs/common-feature-request.md",
    "chars": 530,
    "preview": "# 一些常见的 Feature 需求\n\n这有一些常见的 Feature 列表以及相应的 ISSUES,在提新的 ISSUES 之前,如果有相同的 Feature,请在相应的评论区留下评论\n\n- 安全的导航操作符 [#16](https://"
  },
  {
    "path": "docs/faqs/decorators.md",
    "chars": 13,
    "preview": "# Decorators\n"
  },
  {
    "path": "docs/faqs/enums.md",
    "chars": 204,
    "preview": "# 枚举\n\n## `enum` 和 `const enum` 之间的区别是什么?\n\nTODO:`enum` / `const enum` 有如下区别,请看:[https://www.typescriptlang.org/docs/handb"
  },
  {
    "path": "docs/faqs/function.md",
    "chars": 578,
    "preview": "# 函数\n\n## 为什么我不能在解构函数 `function f({ x: number }) { /* ... */ }` 中使用 `x`?\n\n> 我写下这单代码,但是得到了一个错误\n\n```ts\nfunction f({ x: numb"
  },
  {
    "path": "docs/faqs/generics.md",
    "chars": 2005,
    "preview": "# 泛型\n\n## 通过接口 `A<T>`,为什么 `A<string>` 可赋值给 `A<number>`?\n\n> 我写下这段代码,让它抛出一个错误。\n\n```typescript\ninterface Something<T> {\n  na"
  },
  {
    "path": "docs/faqs/glossary-and-terms.md",
    "chars": 6,
    "preview": "# 术语表\n"
  },
  {
    "path": "docs/faqs/jsx-and-react.md",
    "chars": 659,
    "preview": "# JSX 和 React\n\n## 我写了声明 `declare var MyComponent: React.Component`,为什么我不能写 `<MyComponent />`\n\n> 我写下了如下代码,为什么会抛出错误?\n\n```t"
  },
  {
    "path": "docs/faqs/modules.md",
    "chars": 964,
    "preview": "# 模块\n\n## 为什么我导入的模块在编译后被删除了?\n\n> 我写了一些这样的代码\n\n```typescript\nimport someModule = require('./myMod');\n\nlet x: someModule.Some"
  },
  {
    "path": "docs/faqs/thing-that-dont-work.md",
    "chars": 955,
    "preview": "# 一些不能按预期工作的代码\n\n## 你应该像这样发出一些类,以便于他们拥有真正的私有成员\n\n> 如果我写下一些以下代码\n\n```ts\nclass Foo {\n  private x = 0;\n  increment(): number {"
  },
  {
    "path": "docs/faqs/tsconfig-behavior.md",
    "chars": 1379,
    "preview": "# `tsconfig.json` 的行为\n\n## 为什么把一个文件放入「exclude」选项中,它仍然会被编译器选中?\n\n`tsconfig.json` 将会把一个文件夹转换为「项目」,如果不指定任何 `exclude` 或者 `file"
  },
  {
    "path": "docs/faqs/type-guards.md",
    "chars": 514,
    "preview": "# 类型守卫\n\n## 为什么 `x instanceof Foo` 不能将 `x` 的类型缩小至 `Foo`?\n\n这取决于 `x` 是什么?如果 `x` 的类型不与 `Foo` 兼容,那么缩小 `x` 的类型就毫无意义,所以我们不会这么做。"
  },
  {
    "path": "docs/faqs/type-system-behavior.md",
    "chars": 9286,
    "preview": "# 类型系统的行为\n\n## 什么是结构化类型?\n\nTypeScript 使用**结构化类型**,这个系统并不同于你可能使用过的一些其他流行语言(如:Java、C# 等)的类型系统。\n\n结构化类型系统背后的思想是如果他们的成员类型是兼容的,则"
  },
  {
    "path": "docs/jsx/nonReactJSX.md",
    "chars": 1370,
    "preview": "# 非 React JSX\n\nTypeScript 让你能够以类型安全的方式,在 React 中使用 JSX 之外的其他东西。下面列出了一些可自定义的点,但请注意,这只适用于高级 UI 框架的作者。\n\n- 你可以使用 `\"jsx\":\"pre"
  },
  {
    "path": "docs/jsx/reactJSX.md",
    "chars": 5956,
    "preview": "# React JSX\n\n> [在 React 中使用 TypeScript 的教学视频](https://egghead.io/courses/use-typescript-to-develop-react-applications)\n\n"
  },
  {
    "path": "docs/jsx/support.md",
    "chars": 771,
    "preview": "# 支持 JSX\n\nTypeScript 支持 JSX 转换和代码分析,如果你还不了解 JSX,[官网](https://facebook.github.io/jsx/)上有关于它的摘要:\n\n> JSX is an XML-like syn"
  },
  {
    "path": "docs/new/typescript-3.7.md",
    "chars": 16103,
    "preview": "# TypeScript 3.7\n\n## 可选链(Optional Chaining)\n\n在我们的 issue 追踪器中,可选链在 [issue #16](https://github.com/microsoft/TypeScript/is"
  },
  {
    "path": "docs/new/typescript-3.8.md",
    "chars": 12709,
    "preview": "# TypeScript 3.8\n\n[TypeScript 3.8](http://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html) 将会带来了许"
  },
  {
    "path": "docs/new/typescript-3.9.md",
    "chars": 103,
    "preview": "# TypeScript 3.9\n\n[TypeScript3.9 —— 前端之颠](https://wemp.app/posts/7b99df08-8245-4dbe-8514-c10919779e6a)\n"
  },
  {
    "path": "docs/project/compilationContext.md",
    "chars": 3932,
    "preview": "# 编译上下文\n\n编译上下文算是一个比较花哨的术语,可以用它来给文件分组,告诉 TypeScript 哪些文件是有效的,哪些是无效的。除了有效文件所携带信息外,编译上下文还包含有正在被使用的编译选项的信息。定义这种逻辑分组,一个比较好的方式"
  },
  {
    "path": "docs/project/declarationspaces.md",
    "chars": 911,
    "preview": "# 声明空间\n\n在 TypeScript 里存在两种声明空间:类型声明空间与变量声明空间。下文将分别讨论这两个概念。\n\n## 类型声明空间\n\n类型声明空间包含用来当做类型注解的内容,例如下面的类型声明:\n\n```ts\nclass Foo {"
  },
  {
    "path": "docs/project/dynamicImportExpressions.md",
    "chars": 2084,
    "preview": "# 动态导入表达式\n\n动态导入表达式是 ECMAScript 的一个新功能,它允许你在程序的任意位置异步加载一个模块,TC39 JavaScript 委员会有一个提案,目前处于第四阶段,它被称为 [import() proposal for"
  },
  {
    "path": "docs/project/modules.md",
    "chars": 7102,
    "preview": "# 模块\n\n## 全局模块\n\n在默认情况下,当你开始在一个新的 TypeScript 文件中写下代码时,它处于全局命名空间中。如在 foo.ts 里的以下代码。\n\n```ts\nconst foo = 123;\n```\n\n如果你在相同的项目里"
  },
  {
    "path": "docs/project/namespaces.md",
    "chars": 1126,
    "preview": "# 命名空间\n\n在 JavaScript 使用命名空间时, 这有一个常用的、方便的语法:\n\n```js\n(function(something) {\n  something.foo = 123;\n})(something || (somet"
  },
  {
    "path": "docs/tips/avoidExportDefault.md",
    "chars": 1372,
    "preview": "# `export default` 被认为是有害的\n\n假如你有一个包含以下内容的 `foo.ts` 文件:\n\n```ts\nclass Foo {}\n\nexport default Foo;\n```\n\n你可能会使用 ES6 语法导入它(在 "
  },
  {
    "path": "docs/tips/barrel.md",
    "chars": 1403,
    "preview": "# Barrel\n\nBarrel 就像是一个容器,它的作用是把分散在多个模块的导出合并到一个模块里导出。一般来说,barrel 本身就是一个包含模块的文件,这个模块做的就是重新导出其他(多个)模块导出的东西。\n\n想象一下,在一个库中,具有如"
  },
  {
    "path": "docs/tips/bind.md",
    "chars": 1407,
    "preview": "# Bind 是有害的\n\n::: tip\n译者注:在这个 [PR](https://github.com/Microsoft/TypeScript/pull/27028?from=timeline&isappinstalled=0) 下,已"
  },
  {
    "path": "docs/tips/buildToggles.md",
    "chars": 1077,
    "preview": "# 构建切换\n\n根据 JavaScript 项目的运行环境进行切换环境变量是很常见的,通过 webpack 可以很轻松地做到这一点,因为它支持基于环境变量的死代码排除。\n\n在你的 `package.json script` 里,添加不同的编"
  },
  {
    "path": "docs/tips/classAreUseful.md",
    "chars": 878,
    "preview": "# 类是有用的\n\n以下结构在应用中很常见:\n\n```ts\nfunction foo() {\n  let someProperty;\n\n  // 一些其他的初始化代码\n\n  function someMethod() {\n    // 用 s"
  },
  {
    "path": "docs/tips/covarianceAndContravariance.md",
    "chars": 2416,
    "preview": "# 协变与逆变\n\n> [原文链接: what are covariance and contravariance](https://www.stephanboyer.com/post/132/what-are-covariance-and-"
  },
  {
    "path": "docs/tips/createArrays.md",
    "chars": 201,
    "preview": "# 创建数组\n\n创建数组十分简单:\n\n```ts\nconst foo: string[] = [];\n```\n\n你也可以在创建数组时使用 ES6 的 `Array.prototype.fill` 方法为数组填充数据:\n\n```ts\ncons"
  },
  {
    "path": "docs/tips/curry.md",
    "chars": 189,
    "preview": "# 柯里化\n\n仅仅需要使用一系列箭头函数:\n\n```ts\n// 一个柯里化函数\nlet add = (x: number) => (y: number) => x + y;\n\n// 简单使用\nadd(123)(456);\n\n// 部分应用\n"
  },
  {
    "path": "docs/tips/functionParameters.md",
    "chars": 421,
    "preview": "# 函数参数\n\n如果你有一个含有很多参数或者相同类型参数的函数,那么你可能需要考虑将函数改为接收对象的形式:\n\n如下一个函数:\n\n```ts\nfunction foo(flagA: boolean, flagB: boolean) {\n  "
  },
  {
    "path": "docs/tips/infer.md",
    "chars": 5623,
    "preview": "# infer\n\n## 介绍\n\n`infer` 最早出现在此 [PR](https://github.com/Microsoft/TypeScript/pull/21496) 中,表示在 `extends` 条件语句中待推断的类型变量。\n\n"
  },
  {
    "path": "docs/tips/lazyObjectLiteralInitialization.md",
    "chars": 1323,
    "preview": "# 对象字面量的惰性初始化\n\n在 JavaScript 中,像这样用字面量初始化对象的写法十分常见:\n\n```ts\nlet foo = {};\nfoo.bar = 123;\nfoo.bas = 'Hello World';\n```\n\n但在 "
  },
  {
    "path": "docs/tips/limitPropertySetters.md",
    "chars": 442,
    "preview": "# 减少 setter 属性的使用\n\n倾向于使用更精确的 `set/get` 函数(如 `setBar`, `getBar`),减少使用 `setter/getter`;\n\n考虑以下代码:\n\n```ts\nfoo.bar = {\n  a: 1"
  },
  {
    "path": "docs/tips/metadata.md",
    "chars": 4811,
    "preview": "# Reflect Metadata\n\n## 基础\n\nReflect Metadata 是 ES7 的一个提案,它主要用来在声明的时候添加和读取元数据。TypeScript 在 1.5+ 的版本已经支持它,你只需要:\n\n- `npm i r"
  },
  {
    "path": "docs/tips/nominalTyping.md",
    "chars": 2348,
    "preview": "# 名义化类型\n\nTypeScript 的类型系统是结构化的,[这也是其主要的优点之一](https://basarat.gitbooks.io/typescript/content/docs/why-typescript.html)。然而"
  },
  {
    "path": "docs/tips/outFileCaution.md",
    "chars": 1631,
    "preview": "# 谨慎使用 `--outFile`\n\n由于以下几点原因,你应该谨慎使用 `--outFile` 选项:\n\n- 运行时的错误;\n- 快速编译;\n- 全局作用域;\n- 难以分析;\n- 难以扩展;\n- `_references`;\n- 代码重用"
  },
  {
    "path": "docs/tips/singletonPatern.md",
    "chars": 948,
    "preview": "# 单例模式\n\n传统的单例模式可以用来解决所有代码必须写到 `class` 中的问题:\n\n```ts\nclass Singleton {\n  private static instance: Singleton;\n  private con"
  },
  {
    "path": "docs/tips/statefulFunctions.md",
    "chars": 531,
    "preview": "# 状态函数\n\n其他编程语言有一个共同特征,它们使用 `static` 关键字来增加函数变量的生命周期(不是范围),使其超出函数的调用范围,如 C 语言中的实现:\n\n```c\nvoid called () {\n    static coun"
  },
  {
    "path": "docs/tips/staticConstructors.md",
    "chars": 187,
    "preview": "# TypeScript 中的静态构造函数\n\nTypeScript 中的 `class` (JavaScript 中的 `class`)没有静态构造函数的功能,但是你可以通过调用它自己来获取相同的效果:\n\n```ts\nclass MyCla"
  },
  {
    "path": "docs/tips/stringBasedEmuns.md",
    "chars": 167,
    "preview": "# 基于字符串的枚举\n\n有时你需要在公共的键下收集一些字符串的集合。在 TypeScript 2.4 以前,它仅支持基于数字类型的枚举,如果你在使用 TypeScript 2.4 以上的版本,你通过可以使用[字符串字面量类型与联合类型组合使"
  },
  {
    "path": "docs/tips/truthy.md",
    "chars": 1201,
    "preview": "# Truthy\n\nJavaScript 有一个 `truthy` 概念,即在某些场景下会被推断为 `true`,例如除 `0` 以外的任何数字:\n\n```ts\nif (123) {\n  // 将会被推断出 `true`\n  console"
  },
  {
    "path": "docs/tips/typeInstantiation.md",
    "chars": 831,
    "preview": "# 泛型的实例化类型\n\n假如你有一个具有泛型参数的类型,如一个类 `Foo`:\n\n```ts\nclass Foo<T> {\n  foo: T;\n}\n```\n\n你想为一个特定的类型创建单独的版本,可以通过将它拷贝到一个新变量里,并且用具体类型"
  },
  {
    "path": "docs/tips/typesafeEventEmitter.md",
    "chars": 1683,
    "preview": "# 类型安全的 Event Emitter\n\n通常来说,在 Node.js 与传统的 JavaScript 里,你有一个单一的 Event Emitter,你可以用它来为不同的事件添加监听器。\n\n```ts\nconst emitter = "
  },
  {
    "path": "docs/typings/ambient.md",
    "chars": 1681,
    "preview": "# 环境声明\n\n正如我们在为什么使用 [TypeScript](https://basarat.gitbooks.io/typescript/content/docs/why-typescript.html) 中所说:\n\n> TypeScr"
  },
  {
    "path": "docs/typings/callable.md",
    "chars": 1503,
    "preview": "# 可调用的\n\n你可以使用类型别名或者接口来表示一个可被调用的类型注解:\n\n```ts\ninterface ReturnString {\n  (): string;\n}\n```\n\n它可以表示一个返回值为 `string` 的函数:\n\n```"
  },
  {
    "path": "docs/typings/discrominatedUnion.md",
    "chars": 4527,
    "preview": "# 辨析联合类型\n\n当类中含有[字面量成员](./literals.md)时,我们可以用该类的属性来辨析联合类型。\n\n作为一个例子,考虑 `Square` 和 `Rectangle` 的联合类型 `Shape`。`Square` 和 `Re"
  },
  {
    "path": "docs/typings/enums.md",
    "chars": 6408,
    "preview": "# 枚举\n\n枚举是组织收集有关联变量的一种方式,许多程序语言(如:c/c#/Java)都有枚举数据类型。下面是定义一个 TypeScript 枚举类型的方式:\n\n```ts\nenum CardSuit {\n  Clubs,\n  Diamon"
  },
  {
    "path": "docs/typings/exceptionsHanding.md",
    "chars": 2723,
    "preview": "# 异常处理\n\nJavaScript 有一个 `Error` 类,用于处理异常。你可以通过 `throw` 关键字来抛出一个错误。然后通过 `try/catch` 块来捕获此错误:\n\n```ts\ntry {\n  throw new Erro"
  },
  {
    "path": "docs/typings/freshness.md",
    "chars": 2401,
    "preview": "# Freshness\n\n为了能让检查对象字面量类型更容易,TypeScript 提供 「[Freshness](https://github.com/Microsoft/TypeScript/pull/3823)」 的概念(它也被称为更严"
  },
  {
    "path": "docs/typings/functions.md",
    "chars": 2998,
    "preview": "# 函数\n\n函数类型在 TypeScript 类型系统中扮演着非常重要的角色,它们是可组合系统的核心构建块。\n\n## 参数注解\n\n你可以注解函数参数,就像你可以注解其他变量一样:\n\n```ts\n// variable annotation\n"
  },
  {
    "path": "docs/typings/generices.md",
    "chars": 4383,
    "preview": "# 泛型\n\n设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:\n\n- 类的实例成员\n- 类的方法\n- 函数参数\n- 函数返回值\n\n## 动机和示例\n\n下面是对一个先进先出的数据结构——队列,在 `TypeScript` 和 `"
  },
  {
    "path": "docs/typings/indexSignatures.md",
    "chars": 5560,
    "preview": "# 索引签名\n\n可以用字符串访问 JavaScript 中的对象(TypeScript 中也一样),用来保存对其他对象的引用。\n\n例如:\n\n```ts\nlet foo: any = {};\nfoo['Hello'] = 'World';\nc"
  },
  {
    "path": "docs/typings/interfaces.md",
    "chars": 1591,
    "preview": "# 接口\n\n接口运行时的影响为 0。在 TypeScript 接口中有很多方式来声明变量的结构。\n\n下面两个是等效的声明, 示例 A 使用内联注解,示例 B 使用接口形式:\n\n```ts\n// 示例 A\ndeclare const myPo"
  },
  {
    "path": "docs/typings/lib.md",
    "chars": 6825,
    "preview": "# `lib.d.ts`\n\n当你安装 `TypeScript` 时,会顺带安装一个 `lib.d.ts` 声明文件。这个文件包含 JavaScript 运行时以及 DOM 中存在各种常见的环境声明。\n\n- 它自动包含在 TypeScript"
  },
  {
    "path": "docs/typings/literals.md",
    "chars": 2160,
    "preview": "# 字面量类型\n\n字面量是 JavaScript 本身提供的一个准确变量。\n\n## 字符串字面量\n\n你可以使用一个字符串字面量作为一个类型:\n\n```ts\nlet foo: 'Hello';\n```\n\n在这里,我们创建了一个被称为 `foo"
  },
  {
    "path": "docs/typings/migrating.md",
    "chars": 2809,
    "preview": "# 从 JavaScript 迁移\n\n首先,假设如下:\n\n- 你了解 JavaScript;\n- 你了解在项目中常用的方式和构建工具(如:webpack)。\n\n有了以上假设,一般来说,将 JavaScript 代码迁移至 TypeScrip"
  },
  {
    "path": "docs/typings/mixins.md",
    "chars": 1714,
    "preview": "# 混合\n\nTypeScript (和 JavaScript) 类只能严格的单继承,因此你不能做:\n\n```ts\nclass User extends Tagged, Timestamped { // ERROR : 不能多重继承\n  //"
  },
  {
    "path": "docs/typings/movingTypes.md",
    "chars": 1661,
    "preview": "# 流动的类型\n\nTypeScript 类型系统非常强大,它支持其他任何单一语言无法实现的类型流动和类型片段。\n\n这是因为 TypeScript 的设计目的之一是让你无缝与像 JavaScript 这类高动态的语言一起工作。在这里,我们介绍"
  },
  {
    "path": "docs/typings/neverType.md",
    "chars": 1541,
    "preview": "# Never\n\n::: tip\n[一个关于 never 的介绍视频](https://egghead.io/lessons/typescript-use-the-never-type-to-avoid-code-with-dead-end"
  },
  {
    "path": "docs/typings/overview.md",
    "chars": 6225,
    "preview": "# 概览\n\n## TypeScript 类型系统\n\n在讨论[为什么使用 TypeScript](https://jkchao.github.io/typescript-book-chinese/#whys) 时,我们表述了 TypeScri"
  },
  {
    "path": "docs/typings/readonly.md",
    "chars": 3177,
    "preview": "# readonly\n\nTypeScript 类型系统允许你在一个接口里使用 `readonly` 来标记属性。它能让你以一种更安全的方式工作(不可预期的改变是很糟糕的):\n\n```ts\nfunction foo(config: { rea"
  },
  {
    "path": "docs/typings/thisType.md",
    "chars": 2328,
    "preview": "# ThisType\n\n通过 `ThisType` 我们可以在对象字面量中键入 `this`,并提供通过上下文类型控制 `this` 类型的便捷方式。它只有在 `--noImplicitThis` 的选项下才有效。\n\n现在,在对象字面量方法"
  },
  {
    "path": "docs/typings/typeAssertion.md",
    "chars": 2110,
    "preview": "# 类型断言\n\nTypeScript 允许你覆盖它的推断,并且能以你任何你想要的方式分析它,这种机制被称为「类型断言」。TypeScript 类型断言用来告诉编译器你比它更了解这个类型,并且它不应该再发出错误。\n\n类型断言的一个常见用例是当"
  },
  {
    "path": "docs/typings/typeCompatibility.md",
    "chars": 6580,
    "preview": "# 类型兼容性\n\n类型兼容性用于确定一个类型是否能赋值给其他类型。\n\n如 `string` 类型与 `number` 类型不兼容:\n\n```ts\nlet str: string = 'Hello';\nlet num: number = 12"
  },
  {
    "path": "docs/typings/typeGuard.md",
    "chars": 2680,
    "preview": "# 类型保护\n\n类型保护允许你使用更小范围下的对象类型。\n\n## typeof\n\nTypeScript 熟知 JavaScript 中 `instanceof` 和 `typeof` 运算符的用法。如果你在一个条件块中使用这些,TypeSc"
  },
  {
    "path": "docs/typings/typeInference.md",
    "chars": 2985,
    "preview": "# 类型推断\n\nTypeScript 能根据一些简单的规则推断(检查)变量的类型,你可以通过实践,很快的了解它们。\n\n## 定义变量\n\n变量的类型,由定义推断:\n\n```ts\nlet foo = 123; // foo 是 'number'"
  },
  {
    "path": "docs/typings/types.md",
    "chars": 890,
    "preview": "# @types\n\n毫无疑问,[DefinitelyTyped](https://github.com/borisyankov/DefinitelyTyped) 是 TypeScript 最大的优势之一,社区已经记录了 90% 的顶级 Ja"
  },
  {
    "path": "package.json",
    "chars": 1423,
    "preview": "{\n  \"name\": \"typescript-book-chinese\",\n  \"version\": \"1.0.0\",\n  \"description\": \"typescript-book-chinese\",\n  \"main\": \"inde"
  }
]

About this extraction

This page contains the full source code of the jkchao/typescript-book-chinese GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 122 files (334.3 KB), approximately 125.8k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!