从对象推断属性(无需类型扩展)

时间:2018-10-03 15:08:19

标签: typescript

  • 我的类型为MrType<T extends boolean>
  • 我有一个功能MrFn(obj?: { lol: boolean }): MrType<typeof obj.lol>

我试图推断所提供的对象(如果有的话)的lol属性是true还是false

但是由于类型变宽,我撞墙了

type Magic<T> = T extends { lol: infer U } ? U : false;

const trueObj = { lol: true };
const falseObj = { lol: false };

// should pass
const a: Magic<typeof trueObj> = true; // ok
const b: Magic<typeof falseObj> = false; // ok
const c: Magic<{ lol: true }> = true; // ok
const d: Magic<{ lol: false }> = false; // ok

// should fail
const e: Magic<typeof falseObj> = true; // does not fail
const f: Magic<typeof trueObj> = false; // does not fail
const g: Magic<{ lol: false }> = true; // ok (fails)
const h: Magic<{ lol: true }> = false; // ok (fails)

我的trueObjfalseObj的属性推断为boolean,这意味着我的Magic<T>无法检测到您设置了true还是{{1 }}

是否可以纠正我的解决方案,或者这是TS中的限制?

2 个答案:

答案 0 :(得分:0)

如果值是可变的(并且constfunction makeLol<T extends boolean>(o: { lol: T }) { return o } const trueObj = makeLol({ lol: true }); // typed as { lol: true } const falseObj = makeLol({ lol: false }); // typed as { lol: false } ,则该对象仍是可变的),Typescript将不使用文字。

最简单的解决方案是使用将推断属性的正确文字类型的函数来更改创建对象的方式:

<pre>
  var nodemailer = require("nodemailer");
  sails.log.debug("try to send mail");
  var smtpTransport = nodemailer.createTransport("SMTP", {
      service: "Gmail",
      auth: {
        XOAuth2: {
          user: "xxx@gmail.com", // Your gmail address.
          clientId: "YOUR_CLIENT_ID",
          clientSecret: "YOUR_CLIENT_SECRET",
          refreshToken: "REFRESH_TOKEN_YOU_JUST_FOUND"
        }
      }
    });

  var mailOptions = {
      from: "xxx@gmail.com", // sender address
      to: RECEIVER_EMAIL", // list of receivers
      subject: "A_SUBJECT", // Subject line
      // text: ", // plaintext body
      html: htmlBody // html body
    };
  // send mail
    smtpTransport.sendMail(mailOptions, function(error, info) {
      if (error) {
        sails.log.debug(error);
        return res.notOk({
          status: "error",
          msg: "Email sending failed"
        })
      } else {
        console.log("Message %s sent: %s", info.messageId, info.response);
        return res.ok({
          status: "ok",
          msg: "Email sent"
        })
      }
      smtpTransport.close();
    });
</pre>

答案 1 :(得分:0)

您可以在TypeScript 3.4+中使用新的as const类型断言来做到这一点:

type Magic<T> = T extends { lol: infer U } ? U : false;

const trueObj = { lol: true } as const;
const falseObj = { lol: false } as const;

// should pass
const a: Magic<typeof trueObj> = true; // ok
const b: Magic<typeof falseObj> = false; // ok
const c: Magic<{ lol: true }> = true; // ok
const d: Magic<{ lol: false }> = false; // ok

// should fail
const e: Magic<typeof falseObj> = true; // ok (fails)
const f: Magic<typeof trueObj> = false; // ok (fails)
const g: Magic<{ lol: false }> = true; // ok (fails)
const h: Magic<{ lol: true }> = false; // ok (fails)